[英]Addition for binary natural numbers using primitive recursion
Given binary natural numbers, with a zero case a "twice" case and a "twice plus one" case. 给定二进制自然数,零情况下为“两次”情况,“两次加一”情况。 How can one express addition using primitive recursion (using only the function
foldBNat
)? 如何使用原始递归表示添加(仅使用函数
foldBNat
)?
-- zero | n * 2 | n * 2 + 1
data BNat = Z | T BNat | TI BNat
deriving (Show)
foldBNat :: BNat -> t -> (BNat -> t -> t) -> (BNat -> t -> t) -> t
foldBNat n z t ti =
case n of
Z -> z
T m -> t m (foldBNat m z t ti)
TI m -> ti m (foldBNat m z t ti)
div2 :: BNat -> BNat
div2 n = foldBNat n Z (\m _ -> m) (\m _ -> m)
pred :: BNat -> BNat
pred n = foldBNat n Z (\_ r -> TI r) (\m _ -> T m)
succ :: BNat -> BNat
succ n = foldBNat n (TI Z) (\m _ -> TI m) (\_ r -> T r)
Idea: To compute a + b
, we need to increment b
a
times. 点子:要计算
a + b
,我们需要增加b
a
时代。 So: 所以:
0 + b = b
1 + b = succ b
2 + b = succ (succ b)
3 + b = succ (succ (succ b))
...
We might start out by writing 我们可以从写作开始
plus a b = foldBNat a b (\m r -> ...
But here we get stuck: m
represents half of a
(since a = T m
here, ie a = 2 * m
) and r
is the result of incrementing b
m
times (ie m + b
). 但在这里我们遇到问题:
m
代表的半数a
(因为a = T m
在这里,即a = 2 * m
)和r
是递增的结果b
m
倍(即m + b
)。 There's nothing useful we can do with that. 我们无能为力。 What we want is
a + b = 2*m + b
, which we can't directly obtain from m + b
. 我们想要的是
a + b = 2*m + b
,我们不能直接从m + b
获得。 Applying T
would only give us 2 * (m + b) = 2*m + 2*b
, which is too big, and according to the rules we can't directly recurse on plus
to compute m + (m + b) = 2*m + b
. 应用
T
只会给我们2 * (m + b) = 2*m + 2*b
,这太大了,根据规则我们不能直接递归plus
计算m + (m + b) = 2*m + b
。
What we need is a more direct way of manipulating the number of succ
operations. 我们需要的是一种更直接的方法来操作
succ
操作的数量。
Idea: Don't compute a number directly; 想法:不要直接计算数字; instead compute a function (that increments its argument a certain number of times).
而是计算一个函数(将其参数增加一定次数)。 So:
所以:
incBy 0 = id
incBy 1 = succ
incBy 2 = succ . succ
incBy 3 = succ . succ . succ
...
We can implement that directly: 我们可以直接实现:
incBy :: BNat -> (BNat -> BNat)
incBy n = foldBNat n id (\_ r -> r . r) (\_ r -> succ . r . r)
Here r . r
这里是
r . r
r . r
gives us a function that increments a number twice as often as r
does (by applying r
twice). r . r
给了我们两次尽可能多增加一些功能r
做(通过应用r
两次)。
Now we can simply define addition as: 现在我们可以简单地将添加定义为:
plus :: BNat -> BNat -> BNat
plus n m = (incBy n) m
(which happens to be redundant because plus = incBy
). (这恰好是多余的,因为
plus = incBy
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.