自定义数据类型的Haskell show定义使用的前导引号不一致

自定义数据类型的Haskell show定义使用的前导引号不一致,haskell,show,Haskell,Show,这是我正在编写的代码的简化版本 data ArithExp = Con Int | Add ArithExp ArithExp instance Show ArithExp where show (Con i) = show i show (Add e1 e2) = show "( " ++ show e1 ++ " + " ++ show e2 ++ " )" 所以,如果我运行命令 Add (Con 6) (Con 0)

这是我正在编写的代码的简化版本

data ArithExp = Con Int
          | Add ArithExp ArithExp

instance Show ArithExp where
          show (Con i)     = show i
          show (Add e1 e2) = show "( " ++ show e1 ++ " + " ++ show e2 ++ " )"
所以,如果我运行命令

Add (Con 6) (Con 0)
我想要的输出是:

( 6 + 0 )
但上面的代码显示:

"( "6 + 0 )
据我所知,show函数将第一个字符串中的引号打印为字符,然后在后面的串联中正确使用它们。我觉得这种行为真的不一致。任何有助于我获得正确输出的见解都将不胜感激。 提前谢谢

(Add e1 e2)
分支
中,show
的绑定比
(++)
更紧密,因此您的代码更附带

show (Add e1 e2) = (show "( ") ++ (show e1) ++ " + " ++ (show e2) ++ " )"
诀窍在于,您实际上不需要前导的
show
——您直接生成字符串,只需要将
show
递归应用于
e1
e2

show (Add e1 e2) = "( " ++ show e1 ++ " + " ++ show e2 ++ " )" 

一般来说,
show
将尝试打印您的数据,如果您将其键入ghci,它将计算为等效的数据值。想想在字符串的情况下这意味着什么。如何在中键入字符串值,以便Haskell将其解释为字符串而不是要计算的表达式

以下是一个ghci会议示例,说明了我的意思:

> let myString = "Hello"
> putStrLn $ show myString
=> "Hello"
> :t "Hello"
=> "Hello" :: String
> putStrLn myString
=> Hello
> :t Hello
=> Not in scope: data constructor 'Hello'
由于最初必须在引号中键入字符串,以便将其计算为字符串而不是构造函数表达式,
show
将在其周围加引号,以便您可以将值粘贴回ghci,并获取字符串值而不是构造函数值

虽然在您的示例中,
show
的行为似乎有点违反直觉,但实际上它的行为方式非常一致。希望知道它为什么会这样做能帮助你避免将来遇到这样的问题