警告:非常初学者的问题。如何理解Haskell类型构造函数的有效输入集?
我目前深陷在Haskell的书我读代数类型的部分,我已经遇到了下面的例子:
data Id a =
MkId a deriving (Eq, Show)
idInt :: Id Integer
idInt = MkId 10
idIdentity :: Id (a -> a)
idIdentity = MkId $ \x -> x
OK,坚持住。我不完全了解idIdentity
示例。书中的解释是:
这有点奇怪。类型
Id
接受参数,数据 构造函数MkId
接受相应多态的 类型的参数。因此,为了获得Id Integer
类型的值,我们需要 将a -> Id a
应用于Integer
值。这将a
类型变量绑定到Integer
,并在类型构造函数中使用(->)
,给我们Id Integer
。我们还可以通过将a
绑定到 类型和术语级别中的多态函数来构建MkId
值,该值是身份 函数。
但是等等。为什么只有完全多态的功能?我以前的理解是,a
可以是任何类型。但很显然,受限的多态类型不起作用:(Num a) => a -> a
不会在这里工作,并且GHC错误表明,只有完全态类型或“合格类型”(不知道那些是什么)是有效的:
f :: (Num a) => a -> a
f = undefined
idConsPoly :: Id (Num a) => a -> a
idConsPoly = MkId undefined
Illegal polymorphic or qualified type: Num a => a -> a
Perhaps you intended to use ImpredicativeTypes
In the type signature for ‘idIdentity’:
idIdentity :: Id (Num a => a -> a)
编辑:我是一个笨蛋。我在下面的答案中写下了类型签名,正如@chepner在他的回答中指出的那样。这也解决了我在下面的下一句话中的困惑......
回想起来,这种行为是有道理的,因为我还没有为Id
定义Num
实例。但那么什么解释我能够在idInt :: Id Integer
中应用Integer
这种类型?
所以在一般情况下,我想我的问题是:什么是特定的类型构造函数的有效输入集合?只有完全多态类型?那么什么是“合格类型”呢?等...
限定类型是指具有上下文的那些类型,即以'Constraint => ...'开始。约束是“资格”。 –
进入限定类型和多态的一个好的开端是这篇关于排名n类型的博客文章https://ocharles.org.uk/blog/guest-posts/2014-12-18-rank-n-types.html – epsilonhalbe