Haskell类型构造函数“只是”一个函数吗?
我正在阅读“从第一原则开始的 Haskell 编程”,并找到了一个练习,询问以下 [此处稍微编辑的代码] 是否有效:
module Test where
type Subject = String
type Verb = String
type Object = String
data Sentence =
Sentence Subject Verb Object
deriving (Eq, Show)
a1 = Sentence "I" "like" "cheese"
a2 = Sentence "I" "scream"
我最初的期望是代码会失败,因为在 的定义中a2,Sentence只有两个参数。但是发现GHCi很乐意加载模块。我做了一些实验,发现我现在可以打字了
a3 = a2 "icecream"
并且a3(输入到 GHCi 中)将打印Sentence "I" "scream" "icecream". 另外,如果我查询a2我得到的类型a2 :: Object -> Sentence。所以如果我理解正确的话,a2它的行为就像一个部分应用的函数。
因此,问题是:在所有情况下,类型构造函数是否真的只是一个函数(返回类型值)——与“普通”函数的区别仅在于它必须以大写字符开头?
回答
首先,你在这里谈论的是数据构造函数,而不是类型构造函数。该示例恰好包含一个(空)类型构造函数Sentence和一个三元数据构造函数Sentence。要明确哪个是哪个:
data SentenceTC = SentenceDC Subject Verb Object
SentenceTC是类型构造器,SentenceDC是数据构造器。
所以,问题是:
是否
SentenceDC只是一个函数?
答案是,它是一个函数,而不是“只是”一个函数。它特别是一个单射函数,即参数的每个组合都会导致不同的结果。因此,始终可以从结果SentenceTC值推断出它是哪些参数。这就是在构造函数上进行模式匹配时会发生的情况。
a1Verb :: Verb
a1Verb = case a1 of
Sentence _ v _ -> v
对于一般功能,这是不可能的,例如
n' :: Int
n' = abs n
where n = -3
nNew :: Int
nNew = case n' of
abs n -> n -- error, `abs` can not be used as a pattern match
这也没有意义,因为实际上有两个不同的数字abs等于n'(即,-3和3)。
但是,是的,SentenceDC是一个函数,你可以用它做任何你可以用 type 的其他函数做的事情String -> String -> String -> SentenceTC。反过来也一样:并非您可以使用数据构造函数执行的所有操作也可以使用相同类型的通用函数来完成。
- @chepner, I think it's best to think of a constructor as at least two separate things: a function for constructing values and a pattern for matching on them. Which you get is determined syntactically by where it appears.