当使用' show '而不是整个show字符串时,我如何访问数据类型的字段?



我来自命令式编程,我正在学习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

如何在没有构造函数的情况下访问PrenameSurname的字符串?目前我得到以下输出:

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

此外,你可能会问自己PrenameSurname是否真的需要成为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信息。对我来说,有一个明确说明其功能的自定义函数似乎是更好的方法。

最新更新