形式上能全都变成尾递归,不管你算啥,外面包上一层 k 变成尾递归了
不过尾递归不等于尾递归优化,变换前是O(啥) 。变换后还是O(啥),且更慢,因为加了一堆closure
最近领会到了 CPS 风格程序的一种妙用,或者说滥用。就是部分混杂。常见的cps风格的程序,最后返回的一般是 (k result)。但是这并不是必须的。完全可以 `(,bla ,blabla ,(k result) ,e*)
这样做的效果,就是让调用栈变混乱,强行把内部调用的一部分结果写到外面去。
也就是 我 注入 我自己
(define(simp-pred p)
(letrec
([gen
(λ (program k)
(match program
[(if(true) ,c ,a) (gen c k)]
[(if(false) ,c ,a) (gen a k)]
[(if,p ,c ,a)
(gen p (λ (pcode)
(if(equal?pcode p)
(let([cc (gen c id)]
[ac (gen a id)])
(k `(if,pcode ,cc ,ac)))
(gen `(if,pcode ,c ,a) k))))]
[(begin,e* ... ,e)
(make-begin `(,@(map(λ (x) (gen x id)) e*) ,(gen e k)))]
[,el (k el)]))])
(gen p id)))
(define(id x) x)
(simp-pred '(if(begine1 e2 (if(true)
(true)
(true)))
(begine3 e4 (if(true) e5 e6) e7)
(false)))
(begine1 e2 e3 e4 e5 e7)
;;; (make-begin expr*) flattens begin expressions in expr* and
;;; tacks the symbol begin on the front of the list, except if the
;;; list has one element, in which case it returns the element.
;;; expr* should be nonempty. E.g., (make-begin '(e1)) => e1 and
;;; (make-begin '(e1 (begin (begin e2 e3) e4) e5)) =>
;;; (begin e1 e2 e3 e4 e5).
;;;make-begin 这里可以找到 https://github.com/spiritbear/Grad-School-Code/blob/master/Assignment-3/helpers.ss
看, (simp-pred '(if (begin e1 e2 pred) c a))
能变成 (begin e1 e2 (if pred c a))
今天一不小心写出来的,自己也似懂非懂的,不保证这段没bug啊,图一乐,图一乐。
-----------------------
对于 k 的选取可以非常有创意,可以对子数据块用非常简短的K,id或者id like。然后再在最后拼起数据来。甚至不要害怕丢掉已有的k,如果有把握手头的活已经用完了,k已经发挥其使命了,完全可以在最后的contiuation里不使用 k