RankNTypes类型别名混淆

时间:2016-10-26 02:43:58

标签: haskell types functional-programming higher-rank-types

我试图理解类型约束如何与类型别名一起使用。首先,我们假设我有下一个类型别名:

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

有人能解释一下这里发生了什么吗?我希望功能类型检查是否一致。

1 个答案:

答案 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约束意味着0a并使[0]成为完全有效的NumList a。这意味着,如果first被接受,则所有类型将被居住:

first :: NumList a -> a
first = head

elt :: a
elt = first [0]

特别是Void也是如此:

argh :: Void
argh = elt
确实是啊!