我正在尝试在Haskell中定义一些basic Primitive Recursive函数。为什么我的times
函数递归次数太多次(即eval times[x,y]
导致(x+1)*y
)?我认为我的问题通常是由于对Composition函数的工作原理认识不足。请不要在没有解释的情况下给出答案以澄清我的理解。
import Prelude hiding (pred,and,or,not)
data PR = Z
| S
| P Int
| C PR [PR]
| PR PR PR
deriving Show
eval :: PR -> [Integer] - Integer
eval Z _ = 0
eval S [x] = x+1
eval (P n) xs = nth n xs
eval (C f gs) xs = eval f (map (\g -> eval g xs) gs)
eval (PR g h) (0:xs) = eval g xs
eval (PR g h) (x:xs) = eval h ((x-1) : eval (PR g h) ((x-1):xs) : xs)
nth _ [] = error "nth nil"
nth 0 _ = error "nth index"
nth 1 (x:_) = x
nth (n) (_:xs) = nth (n-1) xs
one = C S [Z]
plus = PR (P 1) (C S [P 2])
times = PR (P 1) (C plus [P 2, P 3])
我已经为times
最近的times = PR (P 1) (C plus[P 2, P 2]
尝试了一些其他的事情,但这是2x*y
的问题。我想“好吧我只会替换其中一个P 2
与} Z
然后它将是x*y
“这实际上使它成为y
的身份函数,我不明白为什么。
答案 0 :(得分:3)
这个时代的定义似乎有效:
times' = PR Z (C plus [P 2, P 3])
*Main> eval times' [6,7]
42
这是有道理的,因为0 * x = 0而不是1。
请注意,我必须更改eval (C ...)
的定义才能进行编译:
eval (C f gs) cs = eval f (map (\g -> eval g cs) gs)
更详细的解释......
我们知道某些times
PR Z h
的格式为h
。
让我们展开eval (PR Z h) (x+1:y:ys)
...
eval (PR z h) (x+1:y:ys)
= eval h ((x+1-1) : eval (PR g h) ((x+1-1):y:ys) : y : ys)
= eval h (x : eval (PR Z h) (x:y:ys) : y : ys)
= eval h (x : x*y : y : ys)
因为通过归纳我们知道eval (PR z h) (x:y:ys) = x*y
。
那么h
必须是什么才能获得(x+1)*y = y+x*y
?我们需要添加y
(P 3
}和x*y
(P 2
),因此我们应将h
定义为:
h = C plus [P 2, P 3]
如果您使用P 1
代替Z
,那么您的基本案例为y
而不是0
:
eval (PR (P 1) ...) (0:y) = eval (P 1) (y) = y
递归保持不变,因此您在答案中的距离为y
。
答案 1 :(得分:3)
假设op
的格式为PR something (C otherThing projections)
。然后,如果x > 0
,
eval op [x,y]
呼叫
eval (C otherThing projections) [x-1, (x-1) `op` y, y]
otherThing
是由排名较高的op
组成的操作。在更简单的情况下,您只想在递归调用的结果(x-1) `op` y
和y
上调用它,因此投影应该选择参数列表的第二个和第三个元素。
因此我们有
times = PR something (C plus [P 2, P 3])
因为我们有递归方程
x*y = (x-1)*y + y
不涉及孤立的x-1
。
现在,当到达基本案例x == 0
时,递归调用应该返回基本结果。对于乘法,当然是0,因此something
应该Z
,独立于y
,而y
不会P 1
给你。{ / p>
因此,作为user5402 said,您应该
times = PR Z (C plus [P 2, P 3])