RankNTypes和教会数字

时间:2016-10-29 02:53:55

标签: haskell types type-theory higher-rank-types

我正在尝试通过给出类似这样的类型来研究Haskell中的教会数字,并认为自然数n基本上是将以下类型的函数应用于值的表达式t次输入n

type Nat = forall t. (t -> t) -> t -> t

有了这个想法,我可以通过以下方式定义zerosuccessorplusmult

zero :: Nat
zero = \f t -> t

succ :: Nat -> Nat
succ n = \f -> f . (n f)

plus :: Nat -> Nat -> Nat
plus m n = \f -> (m f) . (n f)

mult :: Nat -> Nat -> Nat
mult m n = \f -> m (n f) -- Equal to \f -> (m . n) f

-- Pointfree version
mult' :: Nat -> Nat -> Nat
mult' = (.)

当我尝试定义取幂时,我想尝试应用允许我定义乘法的相同推理,即mult m n次应用于1 < /强>

这导致以下代码

exp' :: Nat -> Nat -> Nat
exp' m n = n (mult m) (succ zero)

但是这样做会检查来自GHC的以下错误:

  Couldn't match type ‘t’ with ‘t1’
  ‘t’ is a rigid type variable bound by
    the type signature for:
      exp' :: forall t. Nat -> Nat -> (t -> t) -> t -> t
    at church.lhs:44:3
  ‘t1’ is a rigid type variable bound by
    a type expected by the context:
      forall t1. (t1 -> t1) -> t1 -> t1
    at church.lhs:44:17
  Expected type: ((t -> t) -> t -> t) -> (t -> t) -> t -> t
    Actual type: Nat -> Nat

错误似乎表明类型检查器没有正确地实例化n的类型,理想情况下,类型t应该用另一个(t -> t)实例化以使表达式通过。

令我困惑的是以下代码类型检查:

exp :: Nat -> Nat -> Nat
exp m n = n ((.) m) (succ zero) -- replace mult by (.)

有人会介意解释这里的问题吗?为什么exp'的第一个定义不是类型检查而是第二个exp类型检查?

谢谢!

1 个答案:

答案 0 :(得分:7)

它不起作用的原因是它涉及几个不可预测的实例化,这在Haskell中通常是不允许的。如果你打开*Error: s = separate(predicate.is_positive,[1, -3, -2, 4, 0, -1, 8]) raised exception TypeError: 'int' object is not iterable ,你可以编译它:

-XImpredicativeTypes

第二个版本类型检查因为{-# LANGUAGE ImpredicativeTypes #-} ... exp' :: Nat -> Nat -> Nat exp' m n = n (mult m) (succ zero) 具有更高的排名类型,即使它在定义上等于mult',因此类型检查的进展也不同。由于(.)的类型更简单(排名1),因此类型检查会更频繁地成功。

GHC文档警告(.)不起作用,所以我要小心不要使用它。绕过它的典型方法是简单地使用ImpredicativeTypes

newtype

要查看实际操作中的impredicative实例,可以使用类型化的洞:

newtype Nat' = N { instN :: Nat } 

exp'' :: Nat -> Nat -> Nat
exp'' m n = instN $ n (\(N q) -> N $ mult m q) (N $ succC zero) 

这将报告exp' :: Nat -> Nat -> Nat exp' m n = _ (mult m) (succC zero) 类型,与forall a . (Nat -> Nat) -> Nat -> (a -> a) -> a -> a相同。由于您将(Nat -> Nat) -> Nat -> Nat放在那里,因此必须将此类型与n统一,这涉及使用多边形forall a . (a -> a) -> a -> a实例化类型变量a