Haskell: 如何漂亮地打印不带引号的字符串?
Haskell: How to pretty print a string without quotes?
假设我有这个数据类型:
data SomeDataType a = SomeDataType a
我想向用户显示它的表示(在控制台输出中),所以我需要一个 "pretty print" 函数。我不想使用 show
,因为它会 return 一个表达式,我只想将我的类型的唯一字段的值转换为字符串。
我期待这种行为:
>>> let myintdata = SomeDataType (22::Int)
>>> putStrLn $ prettyPrint myintdata
22
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Alice loves Bob
所以我是这样实现的:
prettyPrint :: Show a => SomeDataType a -> String
prettyPrint (SomeDataType x) = show x
它对数字工作正常,但字符串被引用和转义:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
"Alice" loves "Bob"
此外,我想完全控制将来如何将不同的内容类型转换为字符串。所以,我要创建自己的类型类了!它是这样的:
{-# LANGUAGE FlexibleInstances #-}
data SomeDataType a = SomeDataType a
class PrettyPrint a where
prettyPrint :: a -> String
instance {-# OVERLAPPABLE #-} PrettyPrint a where
-- I don't care about this right now,
-- let's learn how to print strings without quotes first!
prettyPrint = const "Stupid Robot"
instance PrettyPrint String where
prettyPrint = id
instance Show a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x
我对第一次测试很满意:
>>> putStrLn $ prettyPrint "No quotes!"
No quotes!
但是当我尝试漂亮地打印我的数据类型时,不知何故调用了通用实例而不是字符串实例:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Stupid Robot loves Stupid Robot
在这一点上,我怀疑有一种完全不同的方法可以解决这个 "pretty printing" 问题。是这样吗?还是我的代码中遗漏了一些简单明显的错误?
在最后一个实例中,您假设 Show a
并且编译器仅使用此信息为 prettyPrint x
选择合适的实例。
您可以通过要求 PrettyPrint a
作为基础来添加更多信息 class:
instance PrettyPrint a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x
假设我有这个数据类型:
data SomeDataType a = SomeDataType a
我想向用户显示它的表示(在控制台输出中),所以我需要一个 "pretty print" 函数。我不想使用 show
,因为它会 return 一个表达式,我只想将我的类型的唯一字段的值转换为字符串。
我期待这种行为:
>>> let myintdata = SomeDataType (22::Int)
>>> putStrLn $ prettyPrint myintdata
22
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Alice loves Bob
所以我是这样实现的:
prettyPrint :: Show a => SomeDataType a -> String
prettyPrint (SomeDataType x) = show x
它对数字工作正常,但字符串被引用和转义:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
"Alice" loves "Bob"
此外,我想完全控制将来如何将不同的内容类型转换为字符串。所以,我要创建自己的类型类了!它是这样的:
{-# LANGUAGE FlexibleInstances #-}
data SomeDataType a = SomeDataType a
class PrettyPrint a where
prettyPrint :: a -> String
instance {-# OVERLAPPABLE #-} PrettyPrint a where
-- I don't care about this right now,
-- let's learn how to print strings without quotes first!
prettyPrint = const "Stupid Robot"
instance PrettyPrint String where
prettyPrint = id
instance Show a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x
我对第一次测试很满意:
>>> putStrLn $ prettyPrint "No quotes!"
No quotes!
但是当我尝试漂亮地打印我的数据类型时,不知何故调用了通用实例而不是字符串实例:
>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Stupid Robot loves Stupid Robot
在这一点上,我怀疑有一种完全不同的方法可以解决这个 "pretty printing" 问题。是这样吗?还是我的代码中遗漏了一些简单明显的错误?
在最后一个实例中,您假设 Show a
并且编译器仅使用此信息为 prettyPrint x
选择合适的实例。
您可以通过要求 PrettyPrint a
作为基础来添加更多信息 class:
instance PrettyPrint a => PrettyPrint (SomeDataType a) where
prettyPrint (SomeDataType x) = prettyPrint x