Recursion 乔尔·斯波尔斯基在变量悖论中的意思是什么;s值不改变且同时改变?
我大约在8个月前读过这本书,从那时起我就把它作为我应该很快学会的东西的清单。我理解他所说的大部分内容 然而,有一部分我不太确定:Recursion 乔尔·斯波尔斯基在变量悖论中的意思是什么;s值不改变且同时改变?,recursion,scheme,purely-functional,Recursion,Scheme,Purely Functional,我大约在8个月前读过这本书,从那时起我就把它作为我应该很快学会的东西的清单。我理解他所说的大部分内容 然而,有一部分我不太确定: 在一个纯函数程序中,变量的值永远不会改变,但它却一直在改变!悖论 我从中得到的(如果我错了,请原谅我)是他在谈论递归,但递归似乎是一个太简单的概念。以下是我的想法: (define (tail-rec n) (if (= n 1) (display "Done!") (begin (display n) (new
在一个纯函数程序中,变量的值永远不会改变,但它却一直在改变!悖论 我从中得到的(如果我错了,请原谅我)是他在谈论递归,但递归似乎是一个太简单的概念。以下是我的想法:
(define (tail-rec n)
(if (= n 1)
(display "Done!")
(begin
(display n)
(newline)
(tail-rec (- n 1)))))
尾部递归函数tail rec
中的n
值还没有改变。当您查看正在输出的内容时,您会发现它实际上发生了变化。另外,由于函数本身不改变状态对于任何变量,它都意味着它是纯函数。
苏
我说的对吗?
这就是Joel所说的吗?如果不是,请纠正我。为了回答你的问题,Joel的文章确实是在这个上下文中提到递归 然而,您的代码实际上并不是纯功能性的,因为
display
和newline
有副作用。所以我要开始一个切线,给你们一些纯函数递归代码的具体例子
考虑一个函数:
(define (gcd x y)
(if (zero? y)
x
(gcd y (modulo x y))))
这里,每当x
除以y
的余数不为零时,它(tail-)会再次递归调用gcd
,在这个新调用中,x
和y
的值是不同的。(特别是,y
值在每次迭代中变得更小,最终导致基本情况,即x
精确地除以y
,即使y
必须为1才能发生。)
下面是纯函数递归的另一个例子(不过这次也不是尾部递归),用于实现合并两个排序的数字列表的算法:
(define (merge lhs rhs)
(cond ((null? lhs) rhs)
((null? rhs) lhs)
((< (car rhs) (car lhs))
(cons (car rhs) (merge lhs (cdr rhs))))
(else
(cons (car lhs) (merge (cdr lhs) rhs)))))
这是一个典型的例子。每次列表中有2个或更多元素时,将列表分成左右两半,递归到每一半,然后将排序后的两半重新合并在一起。Ah!得了吧,已经有两张反对票了?我不想在这里主观。我只是想要一个答案。如果要让我得到答案,我将删除对Java学校学生的引用。在本例中,n本身不是一个变量,它是函数的形式参数,并且绑定在它自己的范围内。每个调用都有自己不同的N,但这个N永远不会改变。当您解除此调用时,每个n都有其自己的值,该值永远不会更改,但可能与其他n的值不同。而jave,你通常会把它当作i=0的for循环,我怀疑你得到负数的原因是因为你的例子不是纯粹的函数。是的,纯函数不使用赋值,但它们也不会产生副作用,或者有状态或顺序的概念。begin也不是非功能性的,因为它依赖于时间和顺序的概念,而不是评估或函数。
begin
是一种“纯功能性代码味道”,在这种情况下,它很少在副作用上下文之外使用,但它本身并没有本质上的副作用。我从未理解打印
或显示
功能是如何不完全起作用的。这些功能正在改变什么状态?输入/输出缓冲区?@Segfault,无论是打印到终端还是与数据库交互,任何IO都是副作用。纯函数与世界其他部分的唯一交互是通过其参数和返回值。
(define (mergesort lst)
(let ((len (length lst)))
(if (< len 2)
lst
(let-values (((lhs rhs) (split-at lst (quotient len 2))))
(merge (mergesort lhs) (mergesort rhs))))))