�������ۡ�
������my-lengthβ�ݹ�汾�������У�(+ acc 1)���ڵ��±���ֵ�ģ��������ݸ��²�ݹ���á�����Ͳ��ṹ��һ���ݹ��²���ϲ�ļ���������
�����������Ǹ�CPS�������У�ÿһ��ݹ鶼�ᴴ��һ��lambda���ã�����ͨ��collector���Ѽ�������û���ڵ��� ��ֵ�����Ҿ�����ʵ�������ڽ���һ�����ϵĵ���ջ������ԭ���ĵݹ����ջ��(���˾�������αװ��β�ݹ�İ�������β�ݹ顣)
����factorial��CPS��ʽ����ʵ���Բ���Ҫcollector�ġ�����û��CL�� ֻ�и�racket����д������һ��CPS�İ汾��
(define (fact n)(letrec ((F (lambda (n r cont)(cond ((= 0 n) r)(else (cont (- n 1) (* r n) F))))))(cond ((= 0 n) 0)(else (F n 1 F)))))
letrec������labels��define������defun��
On Monday, 21 May 2012 23:54:15 UTC+9, ���� wrote:����ͨ�ĵݹ� ת����β�ݹ���û��ͨ�ÿɸ��Ƶķ����أ�
���綨����һ�������б?�ȵĺ��� (defun my-length (list) (if (null list) 0 (+ (my-length (cdr list)) 1)))�������ԣ�������ͨ�ĵݹ麯���壬ת����β�ݹ�Ҳ�� ������
(defun my-length (list)
(labels ((rec (acc list)
(if (null list)
acc
(rec (+ acc 1)
(cdr list)))))
(rec 0 list)))
������һ�IJ�����Ҳ��(+ acc 1)����Ķ�acc�Ĵ��?Ӧ������ԭ���ĵݹ麯���е�``��һ��''�����г��� �ģ����ڱ��ŵ���acc�ļ����С���һ�IJ���������Ϊԭ���ĵݹ麯���е���һ�ε���ʱ�����ӣ����Կ���һ�� ������ (lambda (v) (+ v 1))������Ļ����Ϳ������Ϊ��β�ݹ�ʵ���Ͼ��ǽ�������ij�ַ�ʽ�� ��������һ�εĵݹ麯������С������ԵIJ���������ĸ����Ե�ʹ�����ӵķ�ʽ������쳲��������� �ĵ�n���ֵ�Ķ��壬ԭ��Ϊhttp://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html�� �Ҹ�ΪLisp������������
(defun factorial-continuation (n cont)
(if (= 0 n)
(funcall cont 1)
(factorial-continuation (- n 1)
(lambda (r)
(funcall cont (* n r))))))
(defun factorial-recursively (n)
(factorial-continuation (- n 1) (lambda (r) (* n r))))
������������ݹ麯��Ļ��ƺ�ȷʵ�����κεݹ麯��ת��Ϊβ�ݹ��أ��о����ԡ�
--
Liutos Love Linux LaTeX Lisp Ling
--�ҵ�GitHub��ҳ��https://github.com/Liutos
Lisp-cn(Lisp�����û���)
CLUG http://lisp.org.cn
--
Lisp-cn(Lisp中文用户组)
CLUG http://lisp.org.cn
应该也不算是伪装成尾递归啦,只是手动完成了编译器的工作。
很多编译器也是把程序转换成CPS,可以把所有的函数都变成尾递归,
因为尾递归其实就是goto,所以这样的程序作优化、分析和运行很方便。
On 05/22/2012 11:52 AM, Nixie O wrote:
讨论讨论。
在上面my-length尾递归版本的例子中,(+ acc 1)是在当下被求值的,并被传递给下层递归调用。这样就不会构成一个递归下层对上层的计算依赖。
但是在上面那个CPS的例子中,每一层递归都会创建一层lambda调用,计算通过collector被搜集起来(没有在当下 求值)。我觉得这实际上是在建造一个堆上的调用栈来代替原本的递归调用栈。(个人觉得它是伪装成尾递归的啊。。。尾递归。)
对于factorial的CPS形式,其实可以不需要collector的。手下没有CL, 只有个racket。我写了另外一个CPS的版本:
(define (fact n)(letrec ((F (lambda (n r cont)(cond ((= 0 n) r)(else (cont (- n 1) (* r n) F))))))(cond ((= 0 n) 0)(else (F n 1 F)))))
letrec类似于labels,define类似于defun。
On Monday, 21 May 2012 23:54:15 UTC+9, 刘滔 wrote:把普通的递归 转换成尾递归有没有通用可复制的方法呢?
例如定义了一个计算列表长度的函数 (defun my-length (list) (if (null list) 0 (+ (my-length (cdr list)) 1)))。很明显,这是普通的递归函数定义,转换成尾递归也很 简单,如下
(defun my-length (list)
(labels ((rec (acc list)
(if (null list)
acc
(rec (+ acc 1)
(cdr list)))))
(rec 0 list)))
本来加一的操作,也即(+ acc 1)这里的对acc的处理,应该是在原来的递归函数中的``上一层''调用中出现 的,现在被放到了acc的计算中。加一的操作可以视为原来的递归函数中的再一次调用时的续延,可以看做一个 匿名函数 (lambda (v) (+ v 1))。这样的话,就可以理解为,尾递归实际上就是将续延以某种方式保 存在了再一次的递归函数调用中。在老赵的博客那里看到的更明显地使用续延的方式来计算斐波纳契数列 的第n项的值的定义,原文为http://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html, 我改为Lisp代码后是这样的
(defun factorial-continuation (n cont)
(if (= 0 n)
(funcall cont 1)
(factorial-continuation (- n 1)
(lambda (r)
(funcall cont (* n r))))))
(defun factorial-recursively (n)
(factorial-continuation (- n 1) (lambda (r) (* n r))))
这样子来定义递归函数的话似乎确实可以把任何递归函数都转换为尾递归呢?感觉可以~
--
Liutos Love Linux LaTeX Lisp Ling
CPS这么神奇?
可以说说尾递归为什么是goto吗?
On Tuesday, 22 May 2012 14:17:07 UTC+9, ���� wrote:
CPS��ô���棿
����˵˵β�ݹ�Ϊʲô��goto��
��Ϊβ�ݹ��Ż���һ������ķ�ʽ����������goto�ķ�ʽ���溯����ջ��
����öԺ���stack frame�Ļ����Ǻ���ͨ��jmpָ����һ��ģ�����gotoô��
Ӧ��Ҳ������αװ��β�ݹ�����ֻ���ֶ�����˱������Ĺ�����
�ܶ������Ҳ�ǰѳ���ת����CPS���������еĺ�����β�ݹ飬
��Ϊβ�ݹ���ʵ����goto����������ij������Ż������������кܷ��㡣
On 05/22/2012 11:52 AM, Nixie O wrote:
�������ۡ�
������my-lengthβ�ݹ�汾�������У�(+ acc 1)���ڵ��±���ֵ�ģ��������ݸ��²�ݹ���á�����Ͳ��ṹ��һ���ݹ��²���ϲ�ļ���������
�����������Ǹ�CPS�������У�ÿһ��ݹ鶼�ᴴ��һ��lambda���ã��� ��ͨ��collector���Ѽ�������û���ڵ��� ��ֵ�����Ҿ�����ʵ�������ڽ���һ�����ϵĵ���ջ������ԭ���ĵݹ����ջ��(���˾�������αװ ��β�ݹ�İ�������β�ݹ顣)
����factorial��CPS��ʽ����ʵ���Բ���Ҫcollector�ġ�����û�� CL�� ֻ�и�racket����д������һ��CPS�İ汾��
(define (fact n)(letrec ((F (lambda (n r cont)(cond ((= 0 n) r)(else (cont (- n 1) (* r n) F))))))(cond ((= 0 n) 0)(else (F n 1 F)))))
letrec������labels��define������defun��
On Monday, 21 May 2012 23:54:15 UTC+9, ���� wrote:
����ͨ�ĵݹ� ת����β�ݹ���û��ͨ�ÿɸ��Ƶķ����أ�
���綨����һ�������б?�ȵĺ��� (defun my-length (list) (if (null list) 0 (+ (my-length (cdr list)) 1)))�������ԣ�������ͨ�ĵݹ麯���壬ת����β�ݹ�Ҳ�� ������
(defun my-length (list)
(labels ((rec (acc list)
(if (null list)
acc
(rec (+ acc 1)
(cdr list)))))
(rec 0 list)))
������һ�IJ�����Ҳ��(+ acc 1)����Ķ�acc�Ĵ��?Ӧ������ԭ���ĵݹ麯���е�``��һ�� ''�����г��� �ģ����ڱ��ŵ���acc�ļ����С���һ�IJ���������Ϊԭ���ĵݹ������е��� һ�ε���ʱ�����ӣ����Կ���һ�� ������ (lambda (v) (+ v 1))������Ļ����Ϳ������Ϊ��β�ݹ�ʵ���Ͼ��ǽ�������ij����ʽ�� ��������һ�εĵݹ麯������С������ԵIJ���������ĸ����Ե�ʹ�����ӵķ�ʽ������쳲��� ������ �ĵ�n���ֵ�Ķ��壬ԭ��Ϊhttp://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html�� �Ҹ�ΪLisp������������
(defun factorial-continuation (n cont)
(if (= 0 n)
(funcall cont 1)
(factorial-continuation (- n 1)
(lambda (r)
(funcall cont (* n r))))))
(defun factorial-recursively (n)
(factorial-continuation (- n 1) (lambda (r) (* n r))))
������������ݹ麯��Ļ��ƺ�ȷʵ�����κεݹ麯��ת��Ϊβ�ݹ��أ��о����ԡ�
--
Liutos Love Linux LaTeX Lisp Ling
--
Liutos Love Linux LaTeX Lisp Ling
�ҵ�GitHub��ҳ��https://github.com/Liutos
其实应该是说在正确实现尾递归的语言中,尾递归必须和goto是等价的,
包括执行的结果、时间开销、栈和堆的空间开销以及其他side effects等等。
On 05/22/2012 01:27 PM, Nixie O wrote:
On Tuesday, 22 May 2012 14:17:07 UTC+9, 刘滔 wrote:
CPS这么神奇?
可以说说尾递归为什么是goto吗?
因为尾递归优化中一个常见的方式就是用类似goto的方式代替函数入栈。
如果不用对函数创建stack frame的话,那和普通的jmp指令是一样的,就是goto么。
在 2012年5月22日 上午11:58,李沛旭 <lip...@gmail.com>写 道:
应该也不算是伪装成尾递归啦,只是手动完成了编译器的工作。
很多编译器也是把程序转换成CPS,可以把所有的函数都变成尾递归,
因为尾递归其实就是goto,所以这样的程序作优化、分析和运行很方便。
On 05/22/2012 11:52 AM, Nixie O wrote:
讨论讨论。
在上面my-length尾递归版本的例子中,(+ acc 1)是在当下被求值的,并被传递给下层递归调用。这样就不会构成一个递归下层对上层的计算依赖。
但是在上面那个CPS的例子中,每一层递归都会创建一层lambda调用,计 算通过collector被搜集起来(没有在当下 求值)。我觉得这实际上是在建造一个堆上的调用栈来代替原本的递归调用栈。(个人觉得它是伪装 成尾递归的啊。。。尾递归。)
对于factorial的CPS形式,其实可以不需要collector的。手下没有 CL, 只有个racket。我写了另外一个CPS的版本:
(define (fact n)(letrec ((F (lambda (n r cont)(cond ((= 0 n) r)(else (cont (- n 1) (* r n) F))))))(cond ((= 0 n) 0)(else (F n 1 F)))))
letrec类似于labels,define类似于defun。
On Monday, 21 May 2012 23:54:15 UTC+9, 刘滔 wrote:
把普通的递归 转换成尾递归有没有通用可复制的方法呢?
例如定义了一个计算列表长度的函数 (defun my-length (list) (if (null list) 0 (+ (my-length (cdr list)) 1)))。很明显,这是普通的递归函数定义,转换成尾递归也很 简单,如下
(defun my-length (list)
(labels ((rec (acc list)
(if (null list)
acc
(rec (+ acc 1)
(cdr list)))))
(rec 0 list)))
本来加一的操作,也即(+ acc 1)这里的对acc的处理,应该是在原来的递归函数中的``上一层 ''调用中出现 的,现在被放到了acc的计算中。加一的操作可以视为原来的递归函数中的再 一次调用时的续延,可以看做一个 匿名函数 (lambda (v) (+ v 1))。这样的话,就可以理解为,尾递归实际上就是将续延以某种方式保 存在了再一次的递归函数调用中。在老赵的博客那里看到的更明显地使用续延的方式来计算斐波纳 契数列 的第n项的值的定义,原文为http://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html, 我改为Lisp代码后是这样的
(defun factorial-continuation (n cont)
(if (= 0 n)
(funcall cont 1)
(factorial-continuation (- n 1)
(lambda (r)
(funcall cont (* n r))))))
(defun factorial-recursively (n)
(factorial-continuation (- n 1) (lambda (r) (* n r))))
这样子来定义递归函数的话似乎确实可以把任何递归函数都转换为尾递归呢?感觉可以~
--
Liutos Love Linux LaTeX Lisp Ling
--
Liutos Love Linux LaTeX Lisp Ling
Ҫ����డ��side effects��Ҫ��˰���
��ʵӦ����˵����ȷʵ��β�ݹ�������У�β�ݹ�����goto�ǵȼ۵ģ�
����ִ�еĽ��ʱ�俪��ջ�ͶѵĿռ俪���Լ�����side effects�ȵȡ�
On 05/22/2012 01:27 PM, Nixie O wrote:
On Tuesday, 22 May 2012 14:17:07 UTC+9, ���� wrote:
CPS��ô���棿
����˵˵β�ݹ�Ϊʲô��goto��
��Ϊβ�ݹ��Ż���һ������ķ�ʽ����������goto�ķ�ʽ���溯����ջ��
����öԺ���stack frame�Ļ����Ǻ���ͨ��jmpָ����һ��ģ�����gotoô��
�� 2012��5��22�� ����11:58�������� <lip...@gmail.com>д ����
Ӧ��Ҳ������αװ��β�ݹ�����ֻ���ֶ�����˱������Ĺ�����
�ܶ������Ҳ�ǰѳ���ת����CPS���������еĺ�����β�ݹ飬
��Ϊβ�ݹ���ʵ����goto����������ij������Ż������������кܷ��㡣
On 05/22/2012 11:52 AM, Nixie O wrote:
�������ۡ�
������my-lengthβ�ݹ�汾�������У�(+ acc 1)���ڵ��±���ֵ�ģ��������ݸ��²�ݹ���á�����Ͳ��ṹ��һ���ݹ��²���ϲ�ļ���������
�����������Ǹ�CPS�������У�ÿһ��ݹ鶼�ᴴ��һ��lambda���ã��� ��ͨ��collector���Ѽ�������û���ڵ��� ��ֵ�����Ҿ�����ʵ�������ڽ���һ�����ϵĵ���ջ������ԭ���ĵݹ����ջ��(���˾� ������αװ ��β�ݹ�İ�������β�ݹ顣)
����factorial��CPS��ʽ����ʵ���Բ���Ҫcollector�ġ��� ��û�� CL�� ֻ�и�racket����д������һ��CPS�İ汾��
(define (fact n)(letrec ((F (lambda (n r cont)(cond ((= 0 n) r)(else (cont (- n 1) (* r n) F))))))(cond ((= 0 n) 0)(else (F n 1 F)))))
letrec������labels��define������defun��
On Monday, 21 May 2012 23:54:15 UTC+9, ���� wrote:
����ͨ�ĵݹ� ת����β�ݹ���û��ͨ�ÿɸ��Ƶķ����أ�
���綨����һ�������б?�ȵĺ��� (defun my-length (list) (if (null list) 0 (+ (my-length (cdr list)) 1)))�������ԣ�������ͨ�ĵݹ麯���壬ת����β�ݹ�Ҳ�� ������
(defun my-length (list)
(labels ((rec (acc list)
(if (null list)
acc
(rec (+ acc 1)
(cdr list)))))
(rec 0 list)))
������һ�IJ�����Ҳ��(+ acc 1)����Ķ�acc�Ĵ��?Ӧ������ԭ���ĵݹ麯���е�``��һ�� ''�����г��� �ģ����ڱ��ŵ���acc�ļ����С���һ�IJ���������Ϊԭ���ĵݹ麯���е��� һ�ε���ʱ�����ӣ����Կ���һ�� ������ (lambda (v) (+ v 1))������Ļ����Ϳ������Ϊ��β�ݹ�ʵ���Ͼ��ǽ�������ij�ַ�ʽ�� ��������һ�εĵݹ麯������С������ԵIJ���������ĸ����Ե�ʹ�����ӵķ�ʽ������ 쳲��� ������ �ĵ�n���ֵ�Ķ��壬ԭ��Ϊhttp://blog.zhaojie.me/2009/03/tail-recursion-and-continuation.html�� �Ҹ�ΪLisp������������
(defun factorial-continuation (n cont)
(if (= 0 n)
(funcall cont 1)
(factorial-continuation (- n 1)
(lambda (r)
(funcall cont (* n r))))))
(defun factorial-recursively (n)
(factorial-continuation (- n 1) (lambda (r) (* n r))))
������������ݹ麯��Ļ��ƺ�ȷʵ�����κεݹ麯��ת��Ϊβ�ݹ��أ� �о����ԡ�
--
Liutos Love Linux LaTeX Lisp Ling
--
Liutos Love Linux LaTeX Lisp Ling
--
Liutos Love Linux LaTeX Lisp Ling
2012/6/5 Liutos <mat.l...@gmail.com>:
我有几个问题想问,
第一、在第一个例子中,普通尾递归的循环不变式是x^i = x * x^(i-1),那么如何根据循环不变式来推知递归的base case是(= n 0)呢?
第二、如何根据循环不变式推知内部的iter函数所需要的参数为x、n和r呢?