這篇來自我在某問答**上的乙個回答。但我覺得這個問題很有價值,我思考和寫作的時間花費了很久。所以我覺得應該儲存起來。
問題是,call/cc的型別是什麼。我們知道,(call/cc (lambda (k) p))有兩種用法,一種是(call/cc (lambda (k) (k a))),例如(+ 1(call/cc (lambda (k) (k 2))));一種是(call/cc (lambda (k) k)),例如(let a (call/cc (lambda (k) k)))。第一種返回a,並送入continuation計算;第二種直接返回乙個continuation。
所以很明顯,call/cc不是只有一種返回型別。兩種用法對應兩種不同型別。第乙個型別是((t1 -> t2) -> t1) -> (t1 -> t2) -> t1,第二種是( (t1 -> t2) -> (t1 -> t2) ) -> (t1 -> t2) -> (t1 -> t2)。
乙個簡單的聯想是,假設x型別是t1->t2, a型別是t1,那麼 ((λ(k) (k a) ) x)和 (λ(k) (k) ) x)分別返回什麼型別?前者是t2,後者是t1->t2。這就是所謂函式一等公民。
回到call/cc。首先要分析整個程式到call/cc之前的位置,按照tapl的表達方式,此時的continuation型別是:
λ k: t1 . t1 -> t2
從這個位置開始,call/cc被呼叫,evaluation rules可表示為:
第一種情況下,type rule為:
γ├ continuation: t1->t2 γ├ a: t1 γ├ λ k: t1 -> t2 . k a
γ├ (call/cc ( λ k . k a )) continuation : t1
第二種情況下type rule:
γ├ continuation: t1->t2 γ├ λ k: t1 -> t2 . k
γ├ (call/cc ( λ k . k)) continuation : t1->t2
即該情況下應該返回t1->t2。
所以結論就是,兩種情況下,返回的型別是不一樣的。call/cc有兩種可能的返回型別,返回哪一種根據不同的(λ (k) process)匹配。一種匹配 k a,另一種匹配 k。是的,這就類似於(λ x . x a ) 與(λ x . x ) 的區別,返回型別不一樣很正常。
在第二種情況下process 直接返回k,但其實程式中call/cc 前後通常會有個let、set!或者其他賦值函式,將這個continuation儲存到某個變數x,程式後面會呼叫(x a)的形式。對於(x a)或者之前的(continuation a),都回到了(t1 -> t2) -> t1 -> t2的套路上,程式最終執行完時兩種情況殊途同歸。
ps,在我看來,call/cc更接近於巨集而非函式,往往純用於結構跳轉而非求值,例如call/cc (lambda (k) (if(something) (k #t)))...)這種用法。它的精華放在(k #t)以外的地方,控制執行還是跳轉。還有,scheme本來就是動態型別系統,型別可以任意的變,分析起來非常痛苦。若當作巨集來看就順眼多了,(...call/cc ...)這個括號裡的內容整體用k乙個符號代替。然後無論哪種用法,遇到k a或k b時,從整個程式中挖掉call/cc括號內容後,a或b代入k所在位置就能得到結果。
參考文獻:
(X)HTML文件應該是什麼樣子
最近,我看到了如此糟糕的html,以至於我想展示html文件的外觀,w3c的要求 絕對最小值定義為 html 4文件由三部分組成 包含html版本資訊的行,宣告性的標頭部分 由head元素分隔 正文,其中包含文件的實際內容。主體可以通過body元素或frameset元素實現。或用 表示 請注意,頁面...
好的領導應該是什麼脾氣
脾氣好的領導看似好,其實是一種自私的表現,不想讓你的下屬變得強大和超越他!我們要記住 1 對你有嚴格要求的的領導,才是真正能幫助你成長的好領導,使我痛苦者,必使我強大。2 再強大的個人,在溫暖的環境中都會失去狼性。3 凡是想方設法逼出員工的能力,開發員工潛力的公司都會公升騰不息,因為在這種環境下,要...
應該是老了
都說人老了,會對新生事物缺乏興趣。我看我目前的狀態,就是這個樣子。看了兩篇文章 中國十大搖滾樂隊 除了張炬 愛你們的男孩都老了 裡面的某些人的名字,當我高中和大學時聽到時,都能沸騰一會兒。乙個二愣子青年,聽到架子鼓的當 當 當。就能瞎激動起來。但,現在不會了。看過汪峰的訪談,他談到和他同輩的搖滾老炮...