首页 > 代码库 > [Scheme]Understanding the Yin-Yang Puzzle
[Scheme]Understanding the Yin-Yang Puzzle
这题目确实比较杀脑细胞...
原题:
1 (let* ((yin 2 ((lambda (cc) (display "@") cc) (call-with-current-continuation (lambda (c) c)))) 3 (yang 4 ((lambda (cc) (display "*") cc) (call-with-current-continuation (lambda (c) c))))) 5 (yin yang))
它会输出“@*@**@***@****@*****@******@*******@********...”
怎么理解呢?
我的方案是移除call/cc,以纯函数的方案重新表示该问题,然后应用代换模型
首先,continuation是什么?
它是一个过程,以一个值为参数,这个值对应call/cc的返回;将实参应用在continuation这个过程上,应该相当于运行程序本身
原则上,continuation中应该包含整个调用栈上各帧及运算的一系列closure,以free variable的方式链接起来,不过由于本题及其简单,大大简化了continuation的近似。
首先,yang-continuation怎么表达?
1 (define (make-yang-continuation yin) 2 (lambda (yang) 3 (putc #\*) 4 (yin yang)) 5 )
意思是,提供yin这个free variable,就返回一个continuation;如果你以参数yang(相当于call/cc的返回)调用continuation,就相当于运行程序(即原题中let*的第二部分)
再来看yin-continuation的表示:
1 (define yin-continuation 2 (lambda (yin) 3 (putc #\@) 4 (let ((yang-continuation (make-yang-continuation yin))) 5 (yang-continuation yang-continuation))) 6 )
这个continuation不需要free variable,因此直接define;它接收一个值yin(即call/cc的返回),再以它为free variable定义yang-continuation,最后,以yang-continuation自身作为参数来继续执行(对应原题中call/cc的参数(lambda (c) c))。
最后,运行整个程序:
1 (yin-continuation yin-continuation)
即,yin-continuation以continuation自身作为yin的初始值,运行整个程序。
完整代码:
1 #lang racket 2 3 (define n 0) 4 (define (putc c) 5 (cond 6 ((< n 100) (set! n (+ n 1)) (display c)) 7 ((= n 100) (set! n (+ n 1)) (newline)) 8 (else ‘ok)) 9 ) 10 11 (define (make-yang-continuation yin) 12 (lambda (yang) 13 (putc #\*) 14 (yin yang)) 15 ) 16 17 (define yin-continuation 18 (lambda (yin) 19 (putc #\@) 20 (let ((yang-continuation (make-yang-continuation yin))) 21 (yang-continuation yang-continuation))) 22 ) 23 24 (yin-continuation yin-continuation)
这里putc打印无限输出串的前100个字符
因为只涉及纯函数,可以开始代换模型了。
下面我将yin-continuation记为y,make-yang-continuation记为m,(y x)可以代换,((m x1) x2)可以代换,前者代换的时候输出@,后者输出*:
(y y) => @ ((m y) (m y)) => @* (y (m y)) => @* @ ((m (m y)) (m (m y))) => @* @* ((m y) (m (m y))) => @* @** (y (m (m y))) => @* @** @ ((m (m (m y))) (m (m (m y)))) => @* @** @* ((m (m y)) (m (m (m y)))) => @* @** @** ((m y) (m (m (m y)))) => @* @** @*** (y (m (m (m y)))) => ...
总算找到一个能把自己糊弄过去的说法...
ps. 有人看不懂scheme,给个lua的翻译版,应该没有理解障碍了(是移除call/cc后的版本,包含了我部分解题思路)。你觉得这谜题容易懂吗:
1 local n = 0 2 function putc(c) 3 if n < 100 then 4 n = n + 1 5 io.write(c) 6 elseif n == 100 then 7 n = n + 1 8 os.exit() 9 end 10 end 11 12 function make_yang_continuation(yin) 13 return function(yang) 14 putc(‘*‘) 15 yin(yang) 16 end 17 end 18 function yin_continuation(yin) 19 putc(‘@‘) 20 local yang_continuation = make_yang_continuation(yin) 21 yang_continuation(yang_continuation) 22 end 23 24 yin_continuation(yin_continuation)