给定以下函数定义并假设所有正整数的类似定义给出一个名为plus的函数的类型定义和代码,它将把两个这样的函数作为参数表示整数并返回一个表示两个输入整数之和的函数。例如。 (plus one two)
应该评估一个带有两个参数f x
并返回(f(f(f x)))
的函数。
one f x = f x
two f x = f (f x)
three f x = f (f (f x)))
等
我是函数式编程的新手,我无法理解这一点。我首先不知道如何定义所有正整数的函数而不将它们写出来(这显然是不可能的)。如果我有plus(sixty, forty)
,我的功能怎么能识别60次被{60}加到x
?
我打算在米兰达写这篇文章,但我对Haskell更熟悉,所以欢迎任何一方的帮助。
答案 0 :(得分:7)
应用等式推理 1 和抽象。
one f x = f x -- :: (a -> b) -> a -> b
two f x = f (f x) -- = f (one f x) -- :: (a -> a) -> a -> a
three f x = f (f (f x)) -- = f (two f x) -- :: (a -> a) -> a -> a
因此,后继函数next
是自然定义的,因此three = next two
。是的,就像在上面的等式中写next two
而不是three
一样简单:
next :: ((b -> c) -> a -> b) -> (b -> c) -> a -> c
-- three f x = next two f x = f (two f x) -- `two` is a formal parameter
next num f x = f (num f x) -- generic name `num`
zero :: t -> a -> a
zero f x = x
这捕捉了继承的模式。 f
将用作后继功能,x
将用作零值。其余的如下。例如,
plus :: (t -> b -> c) -> (t -> a -> b) -> t -> a -> c
plus two one f x = two f (one f x) -- formal parameters two, one
-- = f (f (one f x)) -- an example substitution
-- = f (f (f x) -- uses the global definitions
-- = three f x -- for one, two, three
即。 one f x
将two
用作零值(而不是“通常”x
),因此代表 three
。 “数字”n
表示一系列 n +1
次操作。
上面再次实际定义了一般plus
操作,因为two
和one
只是两个正式的函数参数:
Prelude> plus three two succ 0 -- built-in `succ :: Enum a => a -> a`
5
Prelude> :t plus three two
plus three two :: (a -> a) -> a -> a
Prelude> plus three two (1:) [0]
[1,1,1,1,1,0]
这里要说的关键是函数是在调用时生成值的对象。它本身就是一个不透明的物体。我们应用于它的“观察者”参数,为它意味着为零提供“意义”,或者找到一个继承者,从而定义当我们观察数字值时产生的结果。
1 即。在LHS中使用定义的RHS或LHS与LHS的任何表达式自由替换,如您所见(当然,重命名的变量,不捕获/遮蔽现有的自由变量)。 < / p>
答案 1 :(得分:4)
要将数字转换为数字,您可以使用以下内容:
type Numeral = forall a . (a -> a) -> (a -> a)
toChurch :: Int -> Numeral
toChurch 0 _ x = x
toChurch n f x = f $ toChurch (pred n) f x
fromChurch :: Numeral -> Int
fromChurch numeral = numeral succ 0
答案 2 :(得分:1)
您无需识别该函数调用f
的次数。例如,要实现succ
,它为教会数字加1,你可以这样做:
succ n f x = f (n f x)
然后,您首先使用n
来应用f
但需要多次,然后您自己做最后的f
。您也可以反过来执行此操作,首先自己应用f
,然后让n
完成其余操作。
succ n f x = n f (f x)
您可以使用类似的技术来实现plus
。