3

我正在尝试了解 RankNTypes。

为什么编译器在这种情况下抱怨a不能[a]

> :{
> | tupleF2 :: (forall a . a -> b) -> (a1, a2) -> (b, b)
> | tupleF2 elemF2 (x, y) = (elemF2 x, elemF2 y)
> | :}

> :t tupleF2  tupleF2 :: (forall a. a -> b) -> (a1, a2) -> (b, b)

> :t tupleF2 length

<interactive>:1:9: error:
    • Couldn't match type ‘a’ with ‘[a0]’
      ‘a’ is a rigid type variable bound by
        a type expected by the context:
          forall a. a -> Int
        at <interactive>:1:1-14
      Expected type: a -> Int
        Actual type: [a0] -> Int
    • In the first argument of ‘tupleF2’, namely ‘length’
      In the expression: tupleF2 length

虽然以下类型检查正常?并且t可以t a

> :t tupleF length
tupleF length :: Foldable t => (t a, t a) -> (Int, Int)
:t tupleF
tupleF :: (t -> b) -> (t, t) -> (b, b)

上述编译失败是否仅在启用时发生RankNTypes。了解正在发生的事情的任何指示都会很棒。

谢谢。

4

1 回答 1

5

forall a . a -> bf可以将任何类型的值转换为某个类型的值的a函数的类型b。注意f必须准备好接受任何东西作为输入,即所有这些都必须类型检查

f ()
f 32
f True
f 'a'
f "hello"
f (True, [2], False)

length不满足要求,因为 eglength ()类型错误 -length想要一个可折叠的(如列表)作为输入,并且()不行。

因此,tupleF2 length输入错误。

务实地,注意f只能是一个常数函数,比如

f x = True  -- assuming b = Bool

事实上,参数化保证了只有一个常量函数可以有 type forall a . a -> b。您可以尝试tupleF2 (const True) ((),"hello")获取(True, True).

于 2019-05-09T18:15:10.077 回答