很简单,什么是尾部调用优化?更具体地说,任何人都可以显示一些可以应用的小代码片段,而不是在哪里,并解释为什么?
language-agnostic algorithm recursion tail-recursion tail-call-optimization
我想测试foldl vs foldr.从我所看到的,你应该使用foldl over foldr,因为尾部递归优化.
这是有道理的.但是,运行此测试后,我很困惑:
foldr(使用时间命令时需要0.057秒):
a::a -> [a] -> [a]
a x = ([x] ++ )
main = putStrLn(show ( sum (foldr a [] [0.. 100000])))
Run Code Online (Sandbox Code Playgroud)
foldl(使用time命令时需要0.089s):
b::[b] -> b -> [b]
b xs = ( ++ xs). (\y->[y])
main = putStrLn(show ( sum (foldl b [] [0.. 100000])))
Run Code Online (Sandbox Code Playgroud)
很明显,这个例子很简单,但我很困惑为什么foldr击败foldl.这不应该是foldl获胜的明显案例吗?
在构建列表时,描述第一个典型元素,然后将其纳入自然递归.
"自然递归"的确切定义是什么?我问的原因是因为我正在接受Daniel Friedman的编程语言原则课程,以下代码不被认为是"自然递归":
(define (plus x y)
(if (zero? y) x
(plus (add1 x) (sub1 y))))
Run Code Online (Sandbox Code Playgroud)
但是,以下代码被认为是"自然递归":
(define (plus x y)
(if (zero? y) x
(add1 (plus x (sub1 y)))))
Run Code Online (Sandbox Code Playgroud)
我更喜欢"非自然递归"代码,因为它是尾递归的.但是,这样的代码被认为是诅咒.当我问到为什么我们不应该以尾递归形式编写函数时,副教师简单地回答说:"你不要乱用自然递归."
以"自然递归"形式编写函数有什么好处?
如何在不使用lambda演算的递归的情况下编写阶乘函数?这意味着数学符号不能在任何特定的编程语言中实现.
一个简单的功能如下:
const L = a => L;
Run Code Online (Sandbox Code Playgroud)
形式
L
L(1)
L(1)(2)
...
Run Code Online (Sandbox Code Playgroud)
这似乎形成一个列表,但实际数据根本不存储,所以如果需要存储数据,例如[1,2],完成任务的最聪明的做法是什么?
const L = (a) => {
// do somthing
return L;
};
Run Code Online (Sandbox Code Playgroud)
我更喜欢这种简洁的箭头功能样式,并且不希望尽可能地破坏外部结构.当然,我理解一些外部结构修改是必需的,但我很好奇什么是可能的,特别是在功能风格而不是OO.
该规范仅用于存储功能链的数据.
有任何想法吗?谢谢.
最初最简单的方法是:
const L = (a) => {
L.val = a;
return L;
};
L.val = L;
Run Code Online (Sandbox Code Playgroud)
可以做一些,但没有数据积累.
{ [Function: L] val: [Circular] }
{ [Function: L] val: 1 }
{ [Function: L] val: 2 }
Run Code Online (Sandbox Code Playgroud)
注意:
每个列表应该独立于积累.
L(3)(4)
Run Code Online (Sandbox Code Playgroud)
将返回[3,4]不[2,3,3,4]与之前累积的其他列表.
recursion ×2
algorithm ×1
chain ×1
combinators ×1
fold ×1
haskell ×1
javascript ×1
lambda ×1
lisp ×1
list ×1
object ×1
optimization ×1
racket ×1
scheme ×1