我试图理解类型约束如何与类型别名一起使用。首先,我们假设我有下一个类型别名:
type NumList a = Num a => [a]
我有下一个功能:
addFirst :: a -> NumList a -> NumList
addFirst x (y:_) = x + y
此功能失败,出现下一个错误:
Type.hs:9:13: error:
• No instance for (Num a) arising from a pattern
Possible fix:
add (Num a) to the context of
the type signature for:
addFirst :: a -> NumList a -> a
• In the pattern: y : _
In an equation for ‘addFirst’: ad
这很明显。此问题已在此处描述:
Understanding a rank 2 type alias with a class constraint
我理解为什么我们需要{-# LANGUAGE RankNTypes #-}
才能使这些类型的别名起作用,以及为什么以前的例子不起作用。但是我不明白为什么下一个例子编译得很好(在ghc 8上):
prepend :: a -> NumList a -> NumList a
prepend = (:)
当然,如果我尝试传递错误的值,它会在ghci
中失败:
λ: prepend 1 []
[1]
λ: prepend "xx" []
<interactive>:3:1: error:
• No instance for (Num [Char]) arising from a use of ‘prepend’
• When instantiating ‘it’, initially inferred to have
this overly-general type:
NumList [Char]
NB: This instantiation can be caused by the monomorphism restriction.
似乎在运行时延迟的类型类型检查:(
此外,一些简单的,似乎是同一段代码没有编译:
first :: NumList a -> a
first = head
并产生下一个错误:
Type.hs:12:9: error:
• No instance for (Num a)
Possible fix:
add (Num a) to the context of
the type signature for:
first :: NumList a -> a
• In the expression: head
In an equation for ‘first’: first = head
有人能解释一下这里发生了什么吗?我希望功能类型检查是否一致。
答案 0 :(得分:1)
似乎在运行时延迟的类型类型检查:(
不是真的。这可能有点令人惊讶,因为在加载文件后,你在ghci 中得到了类型错误。但是可以解释一下:文件本身非常好,但这并不意味着 all 你可以使用其中定义的函数构建的表达式将是良好类型的。
更高级别的多态性与它无关。例如(+)
在前奏中定义,但如果您尝试在ghci中评估2 + "argh"
,那么您也会遇到类型错误:
No instance for (Num [Char]) arising from a use of ‘+’
In the expression: 2 + "argh"
In an equation for ‘it’: it = 2 + "argh"
现在,让我们看一下first
的问题:它声称给定一个NumList a
,它可以产生一个a
,没有问题。但我们知道如何凭空建造NumList a
!实际上,Num a
约束意味着0
是a
并使[0]
成为完全有效的NumList a
。这意味着,如果first
被接受,则所有类型将被居住:
first :: NumList a -> a
first = head
elt :: a
elt = first [0]
特别是Void也是如此:
argh :: Void
argh = elt
确实是啊!