RankNTypes和PolyKinds

时间:2015-02-27 19:21:56

标签: haskell polymorphism higher-rank-types polykinds

f1f2之间的区别是什么?

$ ghci -XRankNTypes -XPolyKinds
Prelude> let f1 = undefined :: (forall a        m. m a -> Int) -> Int
Prelude> let f2 = undefined :: (forall (a :: k) m. m a -> Int) -> Int
Prelude> :t f1
f1 :: (forall            (a :: k) (m :: k -> *). m a -> Int) -> Int
Prelude> :t f2
f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int) -> Int

RankNTypes and scope of forall上的此问题相关。从kind polymorphism上的GHC用户指南中获取的示例。

3 个答案:

答案 0 :(得分:11)

f2要求其参数k种类中具有多态性,而f1只是类型本身的多态。所以,如果你定义

{-# LANGUAGE RankNTypes, PolyKinds #-}
f1 = undefined :: (forall a m. m a -> Int) -> Int
f2 = undefined :: (forall (a :: k) m. m a -> Int) -> Int
x = undefined :: forall (a :: *) m. m a -> Int

然后:t f1 x类型正常,而:t f2 x抱怨:

*Main> :t f2 x

<interactive>:1:4:
    Kind incompatibility when matching types:
      m0 :: * -> *
      m :: k -> *
    Expected type: m a -> Int
      Actual type: m0 a0 -> Int
    In the first argument of ‘f2’, namely ‘x’
    In the expression: f2 x

答案 1 :(得分:11)

让我们变得血腥。我们必须量化一切并给出量化领域。价值观有类型;类型级别的东西有种类;种类居住在BOX

f1 :: forall (k :: BOX).
      (forall (a :: k) (m :: k -> *). m a -> Int)
      -> Int

f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int)
      -> Int

现在,在两个示例中都没有显式量化k类型,因此ghc根据是否提及forall (k :: BOX)决定放置k的位置。我并不完全确定我理解或愿意为所述政策辩护。

Ørjan给出了实践中差异的一个很好的例子。让我们也对此感到沮丧。我将编写/\ (a :: k). t来明确表示与forall对应的抽象,并为相应的应用程序f @ type。游戏是我们可以选择@ - ed参数,但我们必须准备好忍受魔鬼可能选择的任何/\个参数。

我们有

x :: forall (a :: *) (m :: * -> *). m a -> Int

因此可能会发现f1 x确实是

f1 @ * (/\ (a :: *) (m :: * -> *). x @ a @ m)

但是,如果我们尝试给f2 x同样的治疗,我们会看到

f2 (/\ (k :: BOX) (a :: k) (m :: k -> *). x @ ?m0 @ ?a0)
?m0 :: *
?a0 :: * -> *
where  m a = m0 a0

Haskell类型系统将类型应用视为纯语法,因此可以解决方程的唯一方法是识别函数并识别参数

(?m0 :: * -> *) = (m :: k -> *)
(?a0 :: *)      = (a :: k)

但这些方程甚至没有得到很好的处理,因为k不能自由选择:它是/\ - 而不是@ - 编辑。

一般来说,为了掌握这些超级多态类型,最好写出所有的量词,然后弄清楚它如何变成你对抗魔鬼的游戏。谁选择什么,以什么顺序。在参数类型中移动forall会改变其选择器,并且通常可以区分胜利和失败。

答案 2 :(得分:3)

f1的类型对其定义设置了更多限制,而f2的类型对其参数设置了更多限制。

即:f1的类型要求其定义k种类中具有多态性,而f2的类型需要其参数k种类中具有多态性。

f1 :: forall (k::BOX). (forall          (a::k) (m::k->*). m a -> Int) -> Int
f2 ::                  (forall (k::BOX) (a::k) (m::k->*). m a -> Int) -> Int

-- Show restriction on *definition*
f1 g = g (Just True)  -- NOT OK. f1 must work for all k, but this assumes k is *
f2 g = g (Just True)  -- OK

-- Show restriction on *argument* (thanks to Ørjan)
x = undefined :: forall (a::*) (m::*->*). m a -> Int
f1 x  -- OK
f2 x  -- NOT OK. the argument for f2 must work for all k, but x only works for *