exp
不能以你的方式书写,因为它需要通过一个
Numeral
作为a的参数
数字
. 这需要有一个
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 n
是
m * (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
,因为
通用量化
:
是一个函数,适用于所有类型
a
,
(a -> a) -> (a -> a)
RankNTypes
type Numeral = forall a. (a -> a) -> (a -> a)
.
这是有道理的:一个教会数字是由它的函数参数重复多少次来定义的。
\f v -> v
电话
f
0次,所以是0,
\f v -> f v
等于1,等等。强制
数字
为所有人工作
确保它可以
只有
关心什么类型
f
和
v
have删除了限制,并允许您编写
(\f v -> "nope") :: Numeral String
我会这样写
{-# LANGUAGE RankNTypes #-}
type Numeral = forall a. (a -> a) -> (a -> a)
_0 :: Numeral
_0 _ x = x
-- The numerals can be defined inductively, with base case 0 and inductive step churchSucc
-- Therefore, it helps to have a _0 constant lying around
churchSucc :: Numeral -> Numeral
churchSucc n f x = f (n f x) -- Cleaner without lambdas everywhere
sum :: Numeral -> Numeral -> Numeral
sum m n f x = m f $ n f x
mult :: Numeral -> Numeral -> Numeral
mult n m = n . m
exp :: Numeral -> Numeral -> Numeral
exp n m = m n
numerify :: Numeral -> Integer
numerify n = n (1 +) 0
toNumeral :: Integer -> Numeral
toNumeral 0 = _0
toNumeral x
| x > 0 = churchSucc $ toNumeral $ x - 1
| otherwise = error "negative argument"
演示:
main = do out "5:" _5
out "2:" _2
out "0:" _0
out "5^0:" $ exp _5 _0
out "5 + 2:" $ sum _5 _2
out "5 * 2:" $ mult _5 _2
out "5^2:" $ exp _5 _2
out "2^5:" $ exp _2 _5
out "(0^2)^5:" $ exp (exp _0 _2) _5
where _2 = toNumeral 2
_5 = toNumeral 5
out :: String -> Numeral -> IO () -- Needed to coax the inferencer
out str n = putStrLn $ str ++ "\t" ++ (show $ numerify n)