我无法找到一种方法来将加法定义为重复递增,尽管这可能是一种无类型语言。这是我的代码:
{-# LANGUAGE RankNTypes #-}
type Church = forall a . (a -> a) -> (a -> a)
zero :: Church
zero = \f -> id
inc :: Church -> Church
inc n = \f -> f . n f
-- This version of addition works
add1 :: Church -> Church -> Church
add1 n m = \f -> n f . m f
-- This version gives me a compilation error
add2 :: Church -> Church -> Church
add2 n m = n inc m
我为add2
获得的编译错误是
Couldn't match type `forall a1. (a1 -> a1) -> a1 -> a1'
with `(a -> a) -> a -> a'
Expected type: ((a -> a) -> a -> a) -> (a -> a) -> a -> a
Actual type: Church -> (a -> a) -> a -> a
In the first argument of `n', namely `inc'
In the expression: n inc m
In an equation for `add2': add2 n m = n inc m
为什么这是一个错误?不是Church
((a->a) -> a -> a)
的同义词吗?
答案 0 :(得分:5)
无论我添加哪种类型的注释,我都无法输入您的代码,尽管我可能不够聪明。 (我也尝试添加ImpredicativeTypes
。)
我认为问题在于定义
type Church = forall a. (a -> a) -> (a -> a)
a
只能用rank-0类型实例化(即内部没有foralls),而Church
本身不是。{1}}。因此,您无法将以这种方式定义的教会数字应用于inc
。
然而,有一个相对简单的解决方法略显冗长但是使一切工作都很好:将Church
变成newtype而不是类型,这样它就可以被视为来自外部的单态。以下一切都有效:
{-# LANGUAGE RankNTypes #-}
newtype Church = Church { runChurch :: forall a . (a -> a) -> (a -> a) }
zero :: Church
zero = Church (\f -> id)
inc :: Church -> Church
inc n = Church (\f -> f . runChurch n f)
add2 :: Church -> Church -> Church
add2 n = runChurch n inc