使用教会数字

时间:2017-08-22 18:11:24

标签: haskell church-encoding

我试图在Haskell中实现教会数字。这是我的代码:

-- Church numerals in Haskell.
type Numeral a = (a -> a) -> (a -> a)

churchSucc :: Numeral a -> Numeral a
churchSucc n f = \x -> f (n f x)

-- Operations with Church numerals.
sum :: Numeral a -> Numeral a -> Numeral a
sum m n = m . churchSucc n

mult :: Numeral a -> Numeral a -> Numeral a
mult n m = n . m

-- Here comes the first problem
-- exp :: Numeral a -> Numeral a -> Numeral a
exp n m = m n

-- Convenience function to "numerify" a Church numeral.
add1 :: Integer -> Integer
add1 = (1 +)

numerify :: Numeral Integer -> Integer
numerify n = n add1 0

-- Here comes the second problem
toNumeral :: Integer -> Numeral Integer
toNumeral 0 = zero
toNumeral (x + 1) = churchSucc (toNumeral x)

我的问题来自取幂。如果我声明toNumeralexp的类型签名,则代码不会编译。但是,如果我评论类型签名声明,一切正常。 toNumeralexp的正确声明是什么?

1 个答案:

答案 0 :(得分:6)

无法按照您的方式编写exp的原因是它涉及将Numeral作为参数传递给Numeral。这需要Numeral (a -> a),但您只有Numeral a。你可以把它写成

exp :: Numeral a -> Numeral (a -> a) -> Numeral a
exp n m = m n

除了toNumeral之类的模式不应该使用之外,x + 1我没有看到什么问题。

toNumeral :: Integer -> Numeral a -- No need to restrict it to Integer
toNumeral 0 = \f v -> v
toNumeral x
  | x > 0 = churchSucc $ toNumeral $ x - 1
  | otherwise = error "negative argument"

此外,您的sum也有问题,因为m . churchSucc nm * (n + 1),所以它应该是:

sum :: Numeral a -> Numeral a -> Numeral a
sum m n f x = m f $ n f x -- Repeat f, n times on x, and then m more times.

但是,教堂数字是适用于所有类型的函数。也就是说,Numeral String不应与Numeral Integer不同,因为Numeral不应该关心它正在处理什么类型。这是通用量化Numeral是一个函数,适用于所有类型a(a -> a) -> (a -> a),使用RankNTypes编写为{ {1}}。

这是有道理的:教会数字由其重复的函数参数的次数来定义。 type Numeral = forall a. (a -> a) -> (a -> a)调用\f v -> v 0次,因此它为0,f为1,等等。强制\f v -> f v适用于所有Numeral,确保它可以这样做。但是,允许a关注哪种类型Numeralf已删除限制,并允许您编写v,即使这显然不是{{1} }}

我会把它写成

(\f v -> "nope") :: Numeral String
相反,它看起来更干净,并且不太可能遇到障碍而不是原始障碍。

演示:

Numeral