2010-09-08 52 views
14

我對Clojure/Lisp宏不是很熟悉。我想編寫apply-recur宏這將具有相同含義(apply recur ...)在Clojure中應用復現宏

我想有這樣的宏沒有真正的需要,但我認爲這是一個很好的鍛鍊。所以我要求你的解決方案。

回答

15

嘛,實在是沒有必要的,如果僅僅是因爲recur不能把可變參數(一recur到函數的頂部需要一個最終seqable說法把所有參數傳遞需要的最後一個參數)。當然,這並不影響練習的有效性。

然而,存在這樣一個「適當」 apply-recur應該大概是處理由任意表達式返回參數seqs和不僅字面一個問題:

;; this should work... 
(apply-recur [1 2 3]) 

;; ...and this should have the same effect... 
(apply-recur (vector 1 2 3)) 

;; ...as should this, if (foo) returns [1 2 3] 
(apply-recur (foo)) 

然而,任意的表達式的值如(foo)是一般來說,在宏觀擴張時間根本不可用。 (也許(vector 1 2 3)可能被認爲始終產生相同的值,但foo可能意味着不同的事情在不同的時間(原因eval不會工作),是let - 綁定本地而不是Var(另一個原因eval不會工作)等)

這樣寫完全通用apply-recur,我們需要能夠確定有多少論點經常recur形式的期望,並有(apply-recur some-expression)擴展到像

(let [seval# some-expression] 
    (recur (nth seval# 0) 
     (nth seval# 1) 
     ... 
     (nth seval# n-1))) ; n-1 being the number of the final parameter 

(最終nth可能需要爲nthnext如果我們正在處理可變參數,這會帶來類似於下一段中所述的問題。另外,最好添加一個斷言來檢查some-expression返回的seqable的長度。)

我不知道任何方法來確定在代碼中的特定位置的recur的適當元數在宏觀擴張時期。這並不意味着它不可用 - 這是編譯器無論如何需要知道的東西,所以也許有一種方法可以從內部提取這些信息。即便如此,任何這樣做的方法幾乎肯定需要依賴於未來可能會改變的實現細節。

因此,結論是:即使完全可以寫這樣一個宏(甚至可能不是這種情況),任何實現都可能非常脆弱。


作爲最後的一句話,寫一個apply-recur這隻會有能力處理文字的(實際上是ARG序列的總體結構將需要給出一個文字;參數本身 - 不一定,所以這可以工作:(apply-recur [foo bar baz]) =>(recur foo bar baz))將會非常簡單。我不會通過放棄解決方案來破壞練習,但作爲提示,請考慮使用[email protected]

3

apply是將另一個函數作爲參數的函數。 recur是一種特殊的形式,不是函數,所以不能傳遞給apply

+1

當然,雖然我把這個問題的意思是「假定一個人不能只寫」(應用重複...),那麼如何編寫一個能夠捕捉這個意圖的宏呢?「 – 2010-09-08 18:15:07

+0

是的,我的意思是這樣,謝謝你們。 – JoeCamel 2010-09-08 18:23:09