25 November 2017

shceme 学习:continuation(3)阴阳谜题

本文是对上面这个链接的补充,对 scheme 的 call/cc 一直处于一知半解的状态,直接看代码吧

continuation

((lambda (x)
   (display "ok")
   (newline)
   x)
 (call/cc (lambda (x) x)))
;;; ok
;;; #<continuation>


;; 上面为什么会返回一个 continuation
;; 我们先来看看不返回 continuation 的情况
((lambda (x)
   (display "ok")
   (newline))
 (call/cc (lambda (x) x)))
;;; ok

((lambda (x)
   (display "ok")
   (newline)
   x)
 (call/cc (lambda (x) (void))))
;;; ok


;; call/cc,直接返回一个 continuation
(call/cc (lambda (x) x))


;; 现在你应该知道为什么会返回一个 continuation 了

continuation 有什么用

(define r #f)
((lambda (x)
   (display "ok")
   (newline)
   x)
 (call/cc (lambda (x) (set! r x) x)))
;; ok
;; #<continuation>

(r 1)
;; ok
;; 1

(call/cc r)
;; ok
;; #<continuation>

(call/cc r)
;; ok
;; #<continuation>

;;; continuation 是什么,这个 continuation 就是 (lambda (x) (display "ok") (newline) x)
;;; 如果我们给这个 continuation 即 r 传一个参数 (r 1),就会执行上面的命令,即 (display "ok") (newline) 1
;;; 如果我们用 call/cc 去呼叫这个 continuation,就相当于恢复了 continuation

来个稍微复杂点的

(define r #f)
((lambda (x)
   (display "ok1")
   (newline)
   x)
 ((lambda (x)
    (display "ok2")
    (newline)
    x)
  (call/cc (lambda (x) (set! r x) x))))

(r 1)
;; ok2
;; ok1
;; 1

(call/cc r)
;; ok2
;; ok1
;; #<continuation>

;;; 在这次,我们保存的 continuation (c2) 和上面的 continuation (c1) 有点不一样
;;; c2 保存的东西相比 c1 来说有点多了

yinyang

(let*
    ((yin ((lambda (x) (display "yin ") x)
           (call/cc (lambda (x) x))))
     (yang ((lambda (x) (display "yang ") x)
            (call/cc (lambda (x) x)))))
  (yin yang))
;; yin 运行后, 返回一个 continuation,这个 continuation 如果接收一个参数,也会继续执行 yin, 然后返回这个参数的返回值
;; (yin yang) 就是将 yang 作为 yin 的参数
;;
;; 那么 yang 是什么,yang 也会返回一个 continuation,这个 continuation 的神奇之处就是,他类似上面于我们上面所说的 c2,他包括了 c1


;;; 第一步
;; 把 (call/cc (lambda (x) x)) 当 x 作为参数包进 (lambda (x) (display "yin ") x) 里面
(display "yin ")
;; 然后执行第二步 x

;;; 第二步
;; 把 ((lambda (x) (display "yang ") x) (call/cc (lambda (x) x))) 作为 yin 的 x 参数包进来
;; 2.1 先将 yang 的 (call/cc (lambda (x) x)) 作为 yang (lambda (x) (display "yang ") x) 的 x 参数
(display "yang ")

;; 2.2 ((lambda (x) (display "yang ") x) (call/cc (lambda (x) x))) 会返回 c2

;;; 第三步
;; 这是一个死循环
;; 在 c1,他等待一个参数
;; 在 c2,他是 c1 还有 c2'
;;
;;; c1 虽然只触发了一次,但是在 c2 里面,又有一个 c1 一直在调用 c2

;;; c1 C2
;;; c1 c2 C2
;;; c1 c2 c2 C2
;;; c1 c2 c2 c2 C2
;;; c1 c2 c2 c2 c2 C2
;;; c1 c2 c2 c2 c2 c2 C2

;;; ==>  c1 c2     c1 c2 c2       c1 c2 c2 c2         c1 c2 c2 c2 c2           c1 c2 c2 c2 c2 c2             c1 c2 c2 c2 c2 c2 c2 ...
;;; ==>  yin yang  yin yang yang  yin yang yang yang  yin yang yang yang yang  yin yang yang yang yang yang  yin yang yang yang yang yang yang ...