如何實現 Call / CC 或者陰陽謎題(Yin Yang Puzzle)?
源代碼好像是來自王垠的博客
這當然是一個死循環啦,不斷地輸出@*@**@***@****...想請教的是,如何使用指令式的語言實現呢? 最好選擇靜態語言啦。。。例如C++, C#, Java, JS 等等。其實用F#,Ruby也都可以啦,看大家方便,謝謝大家 (抱拳
(let* ((yin
((lambda (cc) (display #@) cc) (call-with-current-continuation (lambda (c) c))))
(yang
((lambda (cc) (display #*) cc) (call-with-current-continuation (lambda (c) c)))))
(yin yang))
這裡有一些鏈接可能會有些幫助
Wikepedia of Call / CC
Cont signature document of SML of NJ
A discussion/explanation of Yin Yang Puzzle in StackOverflow
A detailed blog about Yin Yang Puzzle
Await vs Continuation in C#, a discussion in StackOverflow
我很努力地嘗試用C#去實現,但是實在愚鈍,做不到啊...還請大家幫幫忙。 還有順便一問,有什麼別的辦法能訪問王垠的博客嗎?還有很多很精彩的技術博文沒看呢。。。==========================請允許感謝一下,並小結一下。我自己平時是寫C#的,所以特別感謝老趙 @趙劼, 還有@bhuztez 很精彩的圖表分析外加Erlang 版,@Zete 的Ruby 版。向各位大神學習,編程我還要多加學習。就輸出的內容本身是沒有什麼意義的,樓下也有人使用了循環嵌套來實現。我覺得從靜態語言,如C# 的角度上看,這個問題我看有兩個難點: 第一, delegate 可以 用同類的delegate 來做 輸入類型,並且輸出同樣的delegate,我最早一直用Func&
delegate void YinYang(YinYang y = null);
static YinYang Yin = (f) =&> { Console.Write("@"); Yang(f); };
static YinYang Yang = (f) =&> { Console.Write("*"); Yin(f); }; //Try IEnumerable&, or IEnumerable& to simulate the environment?!
Yin(Yang);
, Func& &>,始終無法實現。第二,是它調用的時候,看似互相呼叫,一陰一陽,表面上看應該交替輸出@ 和 * , 但最終因為不斷返回到閉包的環境而輸出越來越多,且環境再疊加。無論如何,再次謝謝大家很精彩的演繹,無論哪個語言,最後做到了 「相互呼叫」 和 「環境重返且疊加」 都值得大讚,很是精彩,直觀優雅! 謝謝!!最後貼上從@bhuztez 那裡來的圖,和拷貝 @趙劼 實現的JS版本。
function MakeYin() {
return cc = function () {
console.log("@");var yang = MakeYang(cc);
return yang(yang);
};
}
function MakeYang(yin){
return cc = function () {
console.log("*");
return yin(cc);
};
}
var yin = MakeYin();
yin(yin);
yin yang puzzle不過是
yin = cc()
echo "@"
yang = cc()
echo "*"
yin(yang)
無非就是cc會產生平行宇宙。這個用 pi-calculus 來表示比較好
proc yin_cc(O,A,B) {
new Yin in {
yin(O,A,B,Yin) | send Yin to Yin
}
}
proc yin(O,A,B,YinCC) {
recv Yin from YinCC;
send A to O;
{ yin(O,A,B,YinCC) | yang_cc(O,A,B,Yin) }
}
proc yang_cc(O,A,B,Yin) {
new Yang in {
yang(O,A,B,Yin,Yang) | send Yang to Yang
}
}
proc yang(O,A,B,Yin,YangCC) {
recv Yang from YangCC;
send B to O;
{ yang(O,A,B,Yin,YangCC) | send Yang to Yin }
}
proc output(O) {
recv X from O;
output(O)
}
proc main() {
new O, A, B in {
output(O) | yin_cc(O,A,B)
}
}
這樣就能直接看圖了 Diagram of π-Calculus
一看就會了,就是這麼簡單
----------------------------------------我理解的執行過程是這樣,不知道為啥這麼理解和Ruby不一樣
1 2
- = cc() | -=1 | -=? | -=1 |
echo "@" @
+ = cc() | +=2 | | +=? |
echo "*" * 3
-(+) | | -=2 | | -=2 |
@
| +=3 | | +=? |
*
| +=3 |
* 4
| -=3 | | -=3 |
@
| +=4 | | +=? |
*
| +=4 |
*
| +=4 |
*
評論不方便貼代碼,直接貼這兒了
(let ((yin (call-with-current-continuation (lambda (c) c))))
(display #@)
(let ((yang (call-with-current-continuation (lambda (c) c))))
(display #*)
(yin yang)
)
)
我改寫的 Javascript 版,和 Scheme 版語句基本能一一對應的,已經非常便於理解了。
改寫的關鍵是使用了 CPS 風格,即所有函數沒有 return 語句,而參數列表的最後一個參數應該被傳入一個函數,通過該函數將返回值傳給下一級處理。
在 CPS 風格下,call/cc 的 Javascript 實現就很簡單了。Scheme 中的 call/cc 只需傳入了一個參數,實際上語言的內部實現會自動生成一個當時的 continuation 隱式的傳給它,這裡把這個過程變成顯式化的了。
在 NodeJS 下可直接運行。
var defer = function(f, context) {
return function() {
var args = arguments;
return process.nextTick(function() {
f.apply(context, args);
});
};
};
var callcc = function(lambda, cps) {
lambda(defer(cps), cps);
};
var yinyang = function() {
// yin"s call-with-current-continuation
callcc(
// (lambda (c) c)
function(c, cps) {
cps(c);
},
// yin"s countinuation
function(value) {
// (let ((yin) ((lambda (cc)
// (display #@) cc)
// (yin"s continuation))))
var yin = (function(cc) {
process.stdout.write("@");
return cc;
})(value);
// yang"s call-with-current-continuation
callcc(
// (lambda (c) c)
function(c, cps) {
cps(c);
},
// yang"s continuation
function(value) {
// (let ((yang) ((lambda (cc)
// (display #*) cc)
// (yang"s continuation))))
var yang = (function(cc) {
process.stdout.write("*");
return cc;
})(value);
// (yin yang)
yin(yang);
}
);
}
);
};
yinyang();
給個簡單的做法
不想做 CPS 變換又要實現 call/cc 的話,把要執行的代碼放數組裡就行了嘛(逃
一個小問題是,這樣的寫法在 JavaScript 里不能像 LISP 里那樣實現一層層嵌套的 let 綁定,所以要在函數參數里存一下
"use strict";
const callcc_yin = (func, t) =&> func((ret) =&> {
yin = ret;
task = t.slice(0);
});
const callcc_yang = (func, y, t) =&> func((ret) =&> {
yin = y;
yang = ret;
task = t.slice(0);
});
let yin, yang;
let task = [
() =&> callcc_yin((ret) =&> ret(ret), task),
() =&> process.stdout.write("@"),
() =&> callcc_yang((ret) =&> ret(ret), yin, task),
() =&> process.stdout.write("*"),
() =&> yin(yang),
];
while (true) {
task.shift()();
}
反正只有兩個 call/cc 函數會改寫 task 數組,我們可以把其它代碼合併進這兩個函數里
"use strict";
const callcc_yin = (func, t) =&> func((ret) =&> {
yin = ret;
task = t.slice(0);
process.stdout.write("@");
});
const callcc_yang = (func, y, t) =&> func((ret) =&> {
yang = ret;
yin = y;
task = t.slice(0);
process.stdout.write("*");
yin(yang);
});
let yin, yang;
let task = [
() =&> callcc_yin((ret) =&> ret(ret), task),
() =&> callcc_yang((ret) =&> ret(ret), yin, task),
];
while (true) {
task.shift()();
}
可以發現,task 數組作為 t 傳進去的時候,內容是固定的(就是當前位置之後的代碼),於是愉快地硬編碼進去
"use strict";
const callcc_yin = (func) =&> func((ret) =&> {
yin = ret;
task = [() =&> callcc_yang((ret) =&> ret(ret), yin)];
process.stdout.write("@");
});
const callcc_yang = (func, y) =&> func((ret) =&> {
yang = ret;
yin = y;
task = [];
process.stdout.write("*");
yin(yang);
});
let yin, yang;
let task = [() =&> callcc_yin((ret) =&> ret(ret))];
while (true) {
task.shift()();
}
那些暫存的變數也可以消去
"use strict";
const callcc_yin = (func) =&> func((yin) =&> {
task = [() =&> callcc_yang((ret) =&> ret(ret), yin)];
process.stdout.write("@");
});
const callcc_yang = (func, yin) =&> func((yang) =&> {
task = [];
process.stdout.write("*");
yin(yang);
});
let task = [() =&> callcc_yin((ret) =&> ret(ret))];
while (true) {
task.shift()();
}
最後,如果你不在意堆棧溢出的話,task 數組其實也可以不要了
"use strict";
const callcc_yin = (func) =&> func((yin) =&> {
process.stdout.write("@");
callcc_yang((ret) =&> ret(ret), yin);
});
const callcc_yang = (func, yin) =&> func((yang) =&> {
process.stdout.write("*");
yin(yang);
});
callcc_yin((ret) =&> ret(ret));
function output(x){
console.log(x);
}
function con(x,y,cont){ return cont(y); }
function yin(cont){
return (function(c,cont2){ return cont2(c); })(
function(v2,cont1){
return (function(cc,cont0){ return con(output(0),cc,cont0); })(v2,cont);
},
function(v2){
return (function(cc,cont0){ return con(output(0),cc,cont0); })(v2,cont);
}
);
}
function yang(cont){
return (function(c,cont2){ return cont2(c); })(
function(v2,cont1){
return (function(cc,cont0){ return con(output(1),cc,cont0); })(v2,cont);
},
function(v2){
return (function(cc,cont0){ return con(output(1),cc,cont0); })(v2,cont);
}
);
}
function f(cont){
return yin(
function(v1){
return yang(function(v2){ return v1(v2,cont); });
}
);
}
f(function(x){return x;});
JavaScript Yin Yang Puzzle
這個實現不是我人工寫的, 是由我的編譯器生成的, 原Yin Yang Puzzle的實現代碼如下(lambda:con(x,y)=y)
(lambda:yin()=(lambda:cc-&>con(output(0),cc))(callcc(lambda:c-&>c)))
(lambda:yang()=(lambda:cc-&>con(output(1),cc))(callcc(lambda:c-&>c)))
(lambda:f()=yin()(yang()))
進行cps編譯變換後源對源編譯成JavaScript, 人工添加了output函數和對函數f進行調用.
上面實現Yin Yang Puzzle的語言和cps編譯變換可以看我的文章CPS變換與CPS變換編譯要生成JavaScript只需要把代碼貼進在線解釋器頁面的文本框然後在console里輸入JavaScript_generator(CPS(parser(lexer(getTextContent($("#code_editor pre.code").get(0))))));
只有支持 call/cc 語言能搞這個魔法... Ruby 版:
require "continuation"
yin, yang =
callcc{|c| c }.tap{ print "@" },
callcc{|c| c }.tap{ print "*" }
yin.(yang)
解釋一下:
obj.tap { ... } 會執行 block 內容, 但最後返回 obj
callcc{|c| c } 相當於 Scheme 里的 (call/cc (lambda (c) c)) 無非就是返回當前 continuation 而已
其實 Scheme 能玩的, Ruby 里都會更簡單...
或者這麼寫:
require "continuation"
callcc{|x|x}.tap{ print "@" }.call
callcc{|x|x}.tap{ print "*" }
輸出也是 @*@**@***@****@*****@******@*******@********@*********@**********@***********
如果像下面這麼寫好像更簡單點?
yin = callcc{|x|x}
print "@"
yang = callcc{|x|x}
print "*"
yin.(yang)
但結果不對... 在 Scheme 里 let 會在棧上壓進去一個新變數, 不管之前有沒有定義同名變數, 所以每個 let 都創造了一個新的世界, 但 Ruby 的變數賦值其實相當於 set! 而不是 let. 為了達成 let 的效果, 可以用 lambda + apply 來實現.
知道了這一點, 我們就可以變換各種姿勢了...
這樣也行:
yin, _, yang, _ = callcc{|x|x}, print("@"), callcc{|x|x}, print("*")
yin.(yang)
這樣也行 (面向組合子編程...):
[callcc{|x|x}, print("@"), callcc{|x|x}, print("*")].compact.reduce :call
這樣也行 (lambda + apply 實現 let):
-&> yin {
print "@"
-&> yang {
print "*"
yin.(yang)
}.(callcc{|x|x})
}.(callcc{|x|x})
-------------- 1月22日更新
一開始我的理解不太對, let* 其實是翻譯成嵌套 let 的, 並行賦值只是碰巧最終效果和 let 一樣而已. 已經更新了上面的一些解釋.// stack free version
var defer = function(f, context) {
return function() {
var args = arguments;
return setTimeout(function() {
f.apply(context, args);
});
};
};
// or simpler version 以下的講解按照簡單版本來
var defer = function(f, context) {
return function() {
var args = arguments;
f.apply(context, args);
};
};
var callcc = function(lambda, cps) {
lambda(defer(cps), cps);
};
var yinyang = function() {
// yin"s call-with-current-continuation
callcc(
// (lambda (c) c)
function(c, cps) {
cps(c);
},
// yin"s countinuation
function(value) {
// (let ((yin) ((lambda (cc)
// (display #@) cc)
// (yin"s continuation))))
var yin = (function(cc) {
console.log("@");
return cc;
})(value);
// yang"s call-with-current-continuation
callcc(
// (lambda (c) c)
function(c, cps) {
cps(c);
},
// yang"s continuation
function(value) {
// (let ((yang) ((lambda (cc)
// (display #*) cc)
// (yang"s continuation))))
var yang = (function(cc) {
console.log("*");
return cc;
})(value);
// (yin yang)
yin(yang);
}
);
}
);
};
yinyang();
這段JS代碼來自 @張護國,我只是把它改成了可以在瀏覽器中執行的代碼。
為什麼我這麼無聊呢?因為瀏覽器執行 JS 代碼可以方便的打斷點。
下面來分析一下這段程序。
我們將從小的結構開始分析。
一、lcc// (lambda (c) c)
var lcc = function(c, cps) {
// c 和 cps 都是函數
cps(c);
}
這個的lcc的作用是先執行c(對c求值),再執行 cps()
二、callcc這個callcc的第一個參數lambda,其實就是lcc。var callcc = function(lambda, cps) {
lambda(defer(cps), cps);
};
所以,每當執行 callcc() 的時候,derfer(cps)先被執行,然後是執行 cps()
// callcc(lcc, cps) is
var v = defer(cps);
cps(v);
強調一個細節,在lcc中,cps(c)的c就是defer(cps)返回值,也就是相當於 cps(defer(cps))
三、cps然後看cps是什麼。cps是陰陽謎題的body,比如yang,是var yang_body = function(value) {
// (let ((yang) ((lambda (cc)
// (display #*) cc)
// (yang"s continuation))))
var yang = (function(cc) {
console.log("*");
return cc;
})(value);
// (yin yang)
yin(yang);
}
var yang = (function(cc) {
console.log("*");
return cc;
})(value);
當我們初始化yang時,效果是這樣的
var yang;
console.log("*");
yang=value;
var defer = function(f, context) {
return function() {
var args = arguments;
f.apply(context, args);
};
};
(針對stack free 版本:setTimeout不帶第二個參數,它的作用其實就是執行完畢當前的函數後,立刻執行這個函數。當然,規範上或許是undefined的行為,但是從設計引擎的角度講,這是最簡單的做法。萬幸,chrome上的行為和我們的猜測一致。)
所以defer(f) 就是f的另一種延遲表達。defer(cps)() 就是立即執行 cps()
六、要把一切連起來
事先說明,如果你在閱讀下面這些分析的時候有困難,請在yin和yang被賦值的那裡打下斷點。當我們執行 yinyang() 時,執行的是 callcc(lcc,yin_body)我們知道,這相當於var value = defer(yin_body);
yin_body(value);
value 是defer(yin_body)的返回值,是一個function,這個function的作用是 will_execute_yin_body。注意,作用不是 execute_yin_body_now。
1. 第一輪接下來,我們在yin_body裡面的第一個語句就是var yin = (function(cc) {
console.log("@");
return cc;
})(value);
我們已經知道,這相當於
var yin;
console.log("@");
yin=value;
var value = defer(yang_body);
yang_body(value);
而yang_body中第一個語句相當於
var yang;
console.log("*");
yang=value;
此時列印了一個 * 星號,然後執行
yin(yang);
接下來,我們分析這個語句的執行效果,我們稱這個語句為第二輪。
2. 第二輪執行yin(yang)就是執行yin_body(yang);
會導致列印 @。
參數是yang,說明裡面的value就是yang也就是第一個語句會變成var yin;
console.log("@");
yin=yang; // yang is defer(yang_body)
第一個語句之後,我們繼續執行yang_body的callcc
第一句相當於var yang;
console.log("*");
yang=value; // defer(yang_body)
列印了 *,yang_body的最後一句是
yin(yang)但是實際上變成了yang_body(yang);
yang_body的第一句相當於
console.log("*");
yang = value; // defer(yang_body)
列印了 *,這是此輪第二次列印 *
然後繼續執行yin(yang),注意,此時的yin是閉包從第一輪的時候catch的,所以依然是原值 defer(yin_body)繼續分析下去,我們就明白陰陽謎題會列印這個結果了。
待續。let callcc=(func,context,continuation)=&>{
let contextCopy=Object.assign({},context)
return func((value)=&>{throw {value,contextCopy,continuation}})
}
let run=(program)=&>{
let context={}
let continuation=0
let callccreturn=undefined
while(true){
try{
program(context,continuation,callccreturn)
break;
}catch(e){
continuation=e.continuation
callccreturn=e.value
context=e.contextCopy
}
}
}
let program=(context,continuation,callccreturn)=&>{
let callccrt=callccreturn
switch(continuation){
case 0:
callccrt=callcc(i=&>i,context,1)
case 1:
context.yin=callccrt
console.log("@")
callccrt=callcc(i=&>i,context,2)
case 2:
context.yang=callccrt
console.log("*")
context.yin(context.yang)
default:
}
}
run(program)
手工將callcc展開後,化簡得到,下面這個函數然後 (A A)就可以了。 @Zete. 這個用ruby怎麼改。
(define (A a)
(display "
")
(display " *")
(a (lambda (aa)
(display " *")
(a aa))))
參考了 hczhcz 的代碼,然後用我寫的腳本語言bajdcc/jMiniLang去實現,jMiniLang支持閉包,所以實現程序也不在話下。
jMiniLang代碼如下:
import "sys.base";
var r = func ~(r) {
return call r(r);
};
var callcc_yang = func ~(f, yin) {
var _yang = func ~(yang) {
call g_print("*");
call yin(yang);
};
return call f(_yang);
};
var callcc_yin = func ~(f) {
var _yin = func ~(yin) {
call g_print("@");
call callcc_yang(r, yin);
};
return call f(_yin);
};
call callcc_yin(r);
然後運行它,結果爆棧了 TVT,我設置的腳本調用棧深是50。
結果是:@*@**@***@****@*****@******@**(爆棧!)
查看了下調用棧:
代碼頁:extern,地址:0,名稱:extern,參數:[],變數:[{}],閉包:{},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}],閉包:{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC],變數:[{}, {3=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:173,名稱:_yang,參數:[函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC],變數:[{}, {5=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC}],閉包:{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC],變數:[{}, {0=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC}],閉包:{},
代碼頁:yinyang,地址:108,名稱:callcc_yang,參數:[函數(yinyang,78)rC, 函數(yinyang,273,{0=函數(yinyang,78)rC})rC],變數:[{4=函數(yinyang,173,{3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC})rC}, {2=函數(yinyang,78)rC, 3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC}],閉包:{},
代碼頁:yinyang,地址:273,名稱:_yin,參數:[函數(yinyang,273,{0=函數(yinyang,78)rC})rC],變數:[{}, {3=函數(yinyang,273,{0=函數(yinyang,78)rC})rC}],閉包:{0=函數(yinyang,78)rC},
代碼頁:yinyang,地址:78,名稱:r,參數:[函數(yinyang,273,{0=函數(yinyang,78)rC})rC],變數:[{}, {0=函數(yinyang,273,{0=函數(yinyang,78)rC})rC}],閉包:{},
代碼頁:yinyang,地址:220,名稱:callcc_yin,參數:[函數(yinyang,78)rC],變數:[{7=函數(yinyang,273,{0=函數(yinyang,78)rC})rC}, {2=函數(yinyang,78)rC}],閉包:{},
代碼頁:yinyang,地址:10,名稱:main,參數:[],變數:[{0=函數(yinyang,78)rC, 1=函數(yinyang,108)rC, 6=函數(yinyang,220)rC}, {}],閉包:{},
代碼頁:yinyang,地址:0,名稱:null,參數:[],變數:[{}],閉包:{}]
調用非常清晰啊~什麼continuation,都包括在上述的閉包裡面。
同樣使用閉包的 Y-Combinator ,jMiniLang也可以實現:
不過如何避免不棧爆,就要用到Trampoline了, 它和Y-Combinator在 https://github.com/bajdcc/jMiniLang/blob/master/src/priv/bajdcc/LALR1/interpret/test/TestInterpret7.java 中。這得讓我好好想想。
用原始的java實現了一個版本,只能說是模擬。用java的對象模擬scheme的閉包,對象的屬性表模擬scheme的詞法環境,對象的方法模擬continuation再入點。
這裡沒有使用任何高階函數,但是手工做了變換的工作。主要的問題是構造函數是個很討厭的存在。abstract class Closure
{ public abstract void run(Closure x);}class Yin extends Closure
{ Closure yin,yang; public Yin() { System.out.print("@"); } public void run(Closure x) { System.out.print("@"); yin = x; yang = new Yang(yin); yin.run(yang); }}class Yang extends Closure
{ Closure yin,yang; public Yang(Closure y) { yin = y; System.out.print("*"); } public void run(Closure x) { yang = x; System.out.print("*"); yin.run(yang); }}public class Main { public static void main(String [] args) { Yin yin = new Yin(); Yang yang = new Yang(yin); yin.run(yang); }}直譯:
delegate YinYang YinYang(YinYang cont);
static YinYang MakeYin()
{
return cout =&>
{
Console.Write("@");
var yang = MakeYang(cout);
return yang(yang);
};
}
static YinYang MakeYang(YinYang yin)
{
return cout =&>
{
Console.Write("*");
return yin(cout);
};
}
static void Main()
{
var yin = MakeYin();
yin(yin);
}
蟹妖,不過臣妾做不到啊,看不明白lisp啊……難道是
// JavaScript
function yin(cc) {
(function (c) {
process.stdout.write("@");
c(yin);
})(cc);
}
function yang(cc) {
(function (c) {
process.stdout.write("*");
c(yang);
})(cc);
}
yin(yang);
輸出是
@*@*@*@*@*@*@*@*@*@*@*@*@*@*@*@*@*@*.....
然後瞬間
RangeError: Maximum call stack size exceeded
我胡謅的,我真的看不懂lisp,捂臉逃
(let ([f
(lambda (g)
(write-char #@)
(let ([h (lambda (x) (write-char #*) (g x))])
(h h)))])
(f f))
經過n次簡化後的陰陽謎題
============================================================================1.將陰陽謎題cps化:經過研究,我發現幾乎任何一個call/cc都可以轉換為等價的cps。所以這裡先將它cps化代碼:((lambda (foo k) (display #@) (k foo))
(call/cc (lambda (bar) bar))
(lambda (yin)
(lambda (foo k) (display #*) (k foo))
(call/cc (lambda (bar) bar))
(lambda (yang) (yin yang))))
然後,發現後面的(lambda (yang) (yin yang))其實等價於yin
於是:((lambda (foo k) (display #@) (k foo))
(call/cc (lambda (bar) bar))
(lambda (yin)
(lambda (foo k) (display #*) (k foo))
(call/cc (lambda (bar) bar))
yin))
2.簡化代碼:
代碼:(define f
(lambda (yin)
(display #@)
((lambda (foo k) (display #*) (k foo))
(call/cc (lambda (bar) bar))
yin)))
((lambda (foo k) (k foo))
(call/cc (lambda (bar) bar))
f)
3.移除call/cc
然後我發現f代表拿到continuation再display之後的continuation。於是把(call/cc ..)改為f,在將(display #@)移到f的函數體里代碼:(define f
(lambda (yin)
(display #@)
((lambda (foo k) (display #*) (k foo))
(call/cc (lambda (bar) bar))
yin)))
((lambda (foo k) (k foo))
f
f)
同樣,下一個call/cc也可以消除
代碼:(define f
(lambda (yin)
(display #@)
(let ([g (lambda (x) (display #*) (yin x))])
((lambda (foo k) (k foo))
g
g))))
((lambda (foo k) (k foo))
f
f)
4.進一步簡化:
((lambda (foo k) (k foo)) A B)可以簡化為(B A)用此方法,即可簡化代碼代碼:(define f
(lambda (yin)
(display #@)
(let ([g (lambda (x) (display #*) (yin x))])
(g g))))
(f f)
再將define改為let:
(let ([f
(lambda (g)
(write-char #@)
(let ([h (lambda (x) (write-char #*) (g x))])
(h h)))])
(f f))
完工
class Yin
{
private event Action OnCall;
readonly Yan _yan = new Yan();
public void DoCall()
{
Console.Write("@");
OnCall += _yan.DoCall;
OnCall?.Invoke();
DoCall();
}
}
class Yan
{
public void DoCall()
{
Console.Write("*");
}
}
class Program
{
static void Main(string[] args)
{
Yin yin = new Yin();
yin.DoCall();
}
}
c# 版的,由於尾遞歸優化.不會爆棧.
看到Cpp1z新的[*this]特性...我就想這個能不能用來做call/cc
姑且寫了一個野指針亂飛的代碼...
測試在這裡 [Wandbox]三へ( へ?? ?)へ ???? 請dalao們指正..
( 然而我還不知道這是不是call/cc...不懂FP )
(反正模板元能實現λ-Calculus, 詳見Matt Might/灼弦巨巨的TemplatePL)
(我很懷疑這代碼有不止一處的UB...)
#include &
#include &
#include &
struct ControlFlow {
template &
auto callcc(F f) {
return f([*this](){ return *this; });
}
struct Yin {
void display() {
std::cout &<&< "@";
}
struct id {
template &
T operator()(T t) {
return t;
}
};
auto yin_callcc() {
return pcf-&>callcc(id{});
}
void new_and_copy() {
auto cf_lambda = yin_callcc();
ControlFlow* pcf2 = new ControlFlow;
auto ccf = cf_lambda();
std::memcpy(pcf2, ccf, sizeof(ccf));
qpcf.push(pcf2);
}
void call() {
display();
new_and_copy();
}
template &
void call(T* other) {
auto pcf2 = qpcf.front();
qpcf.pop();
*pcf = *pcf2;
qpcf.push(other-&>qpcf.front());
pcf-&>seq -= 1;
}
ControlFlow* pcf;
std::queue&
};
struct Yang {
void display() {
std::cout &<&< "*";
}
struct id {
template &
T operator()(T t) {
return t;
}
};
auto yang_callcc() {
return pcf-&>callcc(id{});
}
void new_and_copy() {
auto cf_lambda = yang_callcc();
ControlFlow* pcf2 = new ControlFlow;
auto ccf = cf_lambda();
std::memcpy(pcf2, ccf, sizeof(ccf));
qpcf.push(pcf2);
}
void call() {
display();
new_and_copy();
}
template &
void call(T* other) {
auto pcf2 = qpcf.front();
qpcf.pop();
*pcf = *pcf2;
qpcf.push(other-&>qpcf.front());
pcf-&>seq -= 1;
}
ControlFlow* pcf;
std::queue&
};
void* yin;
void* yang;
int seq;
ControlFlow() {
yin = new Yin();
yang = new Yang();
reinterpret_cast&
reinterpret_cast&
seq = 0;
}
void call() {
switch(seq) {
case 0:
reinterpret_cast&
++seq;
break;
case 1:
reinterpret_cast&
++seq;
break;
case 2:
reinterpret_cast&
++seq;
break;
default:
break;
}
}
};
int main() {
ControlFlow cf;
while(true) {
cf.call();
}
}
function yin(cc) {
setTimeout(function() {
(function(c) {
process.stdout.write("@");
c(yin);
})(cc);
});
}
function yang(cc) {
setTimeout(function() {
(function(c) {
process.stdout.write("*");
c(yang);
})(cc);
});
}
yin(yang);
JS 無Stackover非同步版,我只是把 @Jim Liu的改成非同步而已(捂臉逃
推薦閱讀:
※是否Future/Promise模式 能實現的FRP都能更好的實現?
※如何將MATLAB轉化為C#?
※如何看待2017的 The .NET Language Strategy 去掉了C++/CLI支持?
※什麼情況下使用異常處理?
※C# 中如何有效地釋放內存?