2012-05-11 32 views
4

的短格式func的一個參數注意:不是Why does Clojure recur think it should only have one argument?的重複。我沒有使用循環。爲什麼重複期望使用%&

(def t 
    #(let [[low high] (sort %&)] {:low low :high h})) 

(t 3 2) 
=> {:low 2, :high 3} 

鑑於此功能按預期工作。爲什麼這並不:

(def t 
    #(let [[low high] (sort %&)] 
    (if (= 0 low) 
     nil 
     (do 
     (println {:low low :high high}) 
     (recur low (dec high)))))) 

(t 3 2) 
=> java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 2 

鑑於它說,它期待1種說法我可以猜測,我可以讓它轉動參數到一個收集工作:

(def t 
    #(let [[low high] (sort %&)] 
    (if (= 0 low) 
     nil 
     (do 
     (println {:low low :high high}) 
     (recur [low (dec high)]))))) 

(t 3 2) 
=> {:low 2, :high 3} 
    {:low 2, :high 2} 
    {:low 1, :high 2} 
    {:low 1, :high 1} 
    nil 

.. 。 但爲什麼?

回答

6

這就是它的設計。 Clojure website說:

重複表達式必須完全匹配遞歸點的arity。特別是,如果遞歸點是可變參數fn方法的頂部,則不會收集其餘參數 - 應該傳遞一個seq(或null)。

我相信它被設計成這樣,因爲如果函數本身是給你一個序列(而不是單獨的參數),那麼這將是更自然的易復發的形式,而不是接受一個序列,或東西,可以成爲一個序列。如果情況並非如此,那麼您需要拆分給定的序列以執行遞歸。

你的例子似乎不適合模具,因爲它看起來像你真的只關心有兩個參數,這意味着你真的不需要剩下的參數。您最好明確定義兩個參數,並確定let語句中的哪一個是低和高,而不是對其餘參數進行排序並對它們進行解構。

這是您的代碼,只需最少的修改。我將這兩個顯式參數包裝在一個向量中,然後將它們傳遞給sort(本質上是模仿rest參數),並將兩個參數傳遞給recur。

(def t 
    #(let [[low high] (sort [%1 %2])] 
    (if (= 0 low) 
     nil 
     (do 
     (println {:low low :high high}) 
     (recur low (dec high)))))) 

然而,同時保持易復發的形式,我可能會重構這一點:

(defn t [x y] 
    (let [low (min x y) high (max x y)] 
    (when-not (zero? low) 
     (println {:low low :high high}) 
     (recur low (dec high))))) 
+0

+1的重構版本。 – Gert

+0

爲了好玩,我創建了一個沒有重複發生的懶惰版本:https://www.refheap.com/paste/2691 – Jeremy

+0

感謝您的回答。我查了一下函數定義的特殊格式,但沒有想到再次發現。該代碼只是一個簡單的例子,它做了一些事情。這個問題在代碼高爾夫中出現,我只是想知道爲什麼這樣呢? – status203

相關問題