为什么这个功能无法进行类型检查?

aoc*_*via 5 polymorphism haskell parametric-polymorphism

在关于函数式编程的讲座中,我们看到了以下Haskell函数:

f :: Bool -> Int -> (a -> Int) -> Int
f x y z = if x then y + y else (z x) + (z y)
Run Code Online (Sandbox Code Playgroud)

预计此功能将无法进行类型检查.但是,没有解释这种情况发生的原因.在GHCI中尝试时,我得到以下输出:

Prelude> :l test [1 of 1] Compiling Main             ( test.hs,
interpreted )

test.hs:2:35:
    Couldn't match expected type `a' with actual type `Bool'
      `a' is a rigid type variable bound by
          the type signature for f :: Bool -> Int -> (a -> Int) -> Int
          at test.hs:1:6
    Relevant bindings include
      z :: a -> Int (bound at test.hs:2:7)
      f :: Bool -> Int -> (a -> Int) -> Int (bound at test.hs:2:1)
    In the first argument of `z', namely `x'
    In the first argument of `(+)', namely `(z x)' Failed, modules loaded: none.

为什么会这样?

Don*_*art 9

f :: Bool -> Int -> (a -> Int) -> Int
f x y z = if x then y + y else (z x) + (z y)
Run Code Online (Sandbox Code Playgroud)

类型签名断言我们的函数z在其第一个参数中是多态的.它需要任何类型的值a并返回一个Int.但是,类型变量的范围a也意味着它a在所有用途中必须是相同的类型.a无法在同一个使用站点实例化为不同类型.这是"等级1多态性".

您可以真正阅读该类型:

f :: forall a. Bool -> Int -> (a -> Int) -> Int
Run Code Online (Sandbox Code Playgroud)

所以:

z (x :: Bool) + z (y :: Int)
Run Code Online (Sandbox Code Playgroud)

是无效的,因为它a被限制为两种不同的独立类型.

语言扩展允许我们更改范围,a以便可以将其实例化为多态变量 - 即在同一个使用站点保存不同类型,包括具有多态函数类型:

Prelude> :set -XRankNTypes

Prelude> let f :: Bool -> Int -> (forall a . a -> Int) -> Int 
             f x y z = if x then y + y else (z x) + (z y)
Run Code Online (Sandbox Code Playgroud)

现在该类型a没有全局范围,并且各个实例可以变化.这让我们编写"更多态"功能f并使用它:

Prelude> f True 7 (const 1)
14
Run Code Online (Sandbox Code Playgroud)

这就是更高等级的多态性是多么酷.更多代码重用.

  • 我认为这个答案有点混乱,因为它甚至对于这个`(zx)+(zx)`也不起作用,其中z应用了相同的类型. (2认同)
  • Typechecks与秩N很好.但是语句'a被约束为两个不同的独立类型.有点令人困惑,因为即使`a`被约束为单一类型`(zx + zx)`,它也不会编译默认排名1. (2认同)
  • 实际上,这句话似乎暗示`fxyz = if x然后y + y然后zy`,仅将z应用于一个参数,将使用原始签名传递类型检查.但事实并非如此. (2认同)