我只是在學習 CPS,我正在嘗試將以下程式傳遞給這種風格
mirror Void = Void
mirror (Node x left right) = Node x (mirror right) (mirror left)
據我了解,我必須通過基本情況的延續,并在遞回情況下使用 lambdas 構建構造。對于總和的情況,它將是
cpsadd n 0 k = k n
cpsadd n succ(m) k = cpsadd n m (\v -> k succ(v))
--where k is the continuation, i.e, the stack.
另一個串列示例
mult [] k = k 1
mult (x:xs) k = mult xs (\v -> k (x*v))
從這個意義上說,我有了第一個想法
mirror Void k = k Void
mirror (Node x l r) k = Node x (\v -> k r v) (\w -> k v r)
但是我立即意識到我正在構建樹而沒有通過延續 k。于是我有了第二個想法
mirror Void k = k Void
mirror (Node x l r) k = mirror Node x (\v -> k r v l)
現在我確實通過了延續,但是當我(手動)測驗它時,我沒有達到基本情況,所以它也不起作用。這讓我很困惑,我必須呼叫遞回函式兩次并翻轉它們來制作鏡像。
任何想法?謝謝!
uj5u.com熱心網友回復:
要獲得 CPS,您需要經常執行的一項基本轉換是轉向
f x y = g (h x) y -- non-CPS
進入
f' x y k = h' x (\r -> g' r y) -- CPS
也就是說,每當您需要在運算式中間呼叫函式時,您改為呼叫該函式的 CPS 版本,并將其作為延續 lambda 來完成運算式。因此,讓我們從您的定義開始mirror,并努力實作 CPS。
mirror Void = Void
mirror (Node x left right) = Node x (mirror right) (mirror left)
我會寫[e]來表示運算式e需要轉換為 CPS 形式,并且只要e它已經被轉換。首先讓我們添加k引數,并將實作包裝在括號中以指示它們需要轉換:
mirror Void k = [Void]
mirror (Node x left right) k = [Node x (mirror right) (mirror left)]
轉換 Void 案例很容易:您已經這樣做了。
mirror Void k = k Void
mirror (Node x left right) k = [Node x (mirror right) (mirror left)]
現在我們需要解決對mirror right. 我們立即呼叫它,然后給它一個 lambda(尚未完全轉換):
mirror Void k = k Void
mirror (Node x left right) k = mirror right r
where r right' = [Node x right' (mirror left)]
現在的主體有一個需要解除r的呼叫:mirror left
mirror Void k = k Void
mirror (Node x left right) k = mirror right r
where r right' = mirror left l
where l left' = [Node x right' left']
現在, 的主體l沒有剩余的遞回呼叫,并且具有您想要傳遞的值k,因此最終的轉換很容易:只需呼叫k.
mirror Void k = k Void
mirror (Node x left right) k = mirror right r
where r right' = mirror left l
where l left' = k $ Node x right' left'
如果你愿意,你可以用 lambdas 而不是where子句來寫,但原理是一樣的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/493301.html
