Haskell:如何在不使用引号的情况下美化打印字符串?

6

假设我有这种数据类型:

data SomeDataType a = SomeDataType a

我希望向用户展示它的表示形式(在控制台输出中),因此我需要一个“漂亮打印”函数。我不想使用show,因为它会返回一个表达式,而我只想将我的类型的唯一字段的值转换为字符串。

我期望这种行为:

>>> 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!

但是当我尝试美化打印我的数据类型时,总是会调用通用实例而不是String的实例:

>>> let alice = SomeDataType "Alice"
>>> let bob = SomeDataType "Bob"
>>> putStrLn $ prettyPrint alice ++ " loves " ++ prettyPrint bob
Stupid Robot loves Stupid Robot

目前我怀疑有一种完全不同的方法来解决这个“漂亮打印”问题。是这样吗?还是我在代码中忽略了一些简单明显的错误?


请参见 https://dev59.com/7p3ha4cB1Zd3GeqPRkX1。 - Adam Burke
1个回答

3
在最后一步,你假设 Show a,并且编译器仅使用此信息来选择适当的实例以用于 prettyPrint x
通过将 PrettyPrint a 作为基类要求,您可以添加更多信息:
instance PrettyPrint a => PrettyPrint (SomeDataType a) where
    prettyPrint (SomeDataType x) = prettyPrint x

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接