使用 `show` 而不是整个显示字符串时如何访问数据类型的字段?

How can I access the fields of a data type when using `show` instead of the whole show string?

我是命令式编程出身,正在学习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"

我感到非常沮丧,因为这似乎是一件很简单的事情,我该如何实现呢?

有几种方法可以做到这一点。一种方法是编写一个将名称写入终端的函数,如下所示:

writeName :: Person -> IO ()
writeName (P (Prename p) (Surname s) _) = putStrLn (p ++ " " ++ s)
λ> writeName jondoe 
John Doe

另一种方法是 returns 连接全名作为字符串的函数:

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 信息。拥有一个明确说明其功能的自定义函数对我来说似乎是更好的方法。

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)
     = ...