我来自命令式编程,我正在学习Haskell。我有以下数据类型:
newtype Prename = Prename String deriving (Show)
newtype Surname = Surname String deriving (Show)
data Employment = Employed | Unemployed
data Person = P Prename Surname Employment
jondoe = P (Prename "John") (Surname "Doe") Employed
如何在没有构造函数的情况下访问Prename
和Surname
的字符串?目前我得到以下输出:
show jondoe
"P (Prename"John") (Surname"Doe") (Employed)"
但是我希望它是
show jondoe
"John Doe"
我感到非常沮丧,因为这似乎是一件很简单的事情,我怎么才能做到这一点?
show
是不是得到漂亮的输出。它专门用于生成有效的Haskell代码。现在,"John Doe"
在语法上当然是有效的,但是它没有正确的类型。
也就是说,我个人认为将Show
实例基于自定义智能构造函数是完全可以的,这将使其更具可读性。例如,您可以使用
employee :: Prename -> Surname -> Person
employee pn sn = P pn sn Employed
nonworker :: Prename -> Surname -> Person
nonworker pn sn = P pn sn Unemployed
此外,你可能会问自己Prename
和Surname
是否真的需要成为newtypes
。如果你只是让它们
type Prename = String
type Surname = String
则可以直接打印为…嗯,字符串。现在可以编写Show
实例
instance Show Person where
showsPrec p (P pn sn Employed)
= showParen (p>9)
$ ("employee "++)
. showsPrec 11 pn
. showsPrec 11 sn
showsPrec p (P pn sn Unemployed)
= ...
有几种方法可以做到这一点。一种方法是编写一个函数,将名称写入终端,如下所示:
writeName :: Person -> IO ()
writeName (P (Prename p) (Surname s) _) = putStrLn (p ++ " " ++ s)
λ> writeName jondoe
John Doe
另一种方法是使用一个函数,将连接的全名作为字符串返回:
getFullname :: Person -> String
getFullname (P (Prename p) (Surname s) _) = p ++ " " ++ s
getFullname :: Person -> String
getFullname (P (Prename p) (Surname s) _) = p ++ " " ++ s
第三种方法是为Person
实现Show
的实例,如下所示:
instance Show Person where
show (P (Prename p) (Surname s) _) = p ++ " " ++ s
λ> show jondoe
"John Doe"
但说实话,我不确定以这种方式实现Show
实例是否是个好主意,因为您丢失了Employment
信息。对我来说,有一个明确说明其功能的自定义函数似乎是更好的方法。