2011-10-02 38 views
1

此問題與one I asked recently有關。如何從關閉中定義函數

如果我重寫(fn [n] (fn [x] (apply * (repeat n x))))作爲

(defn power [n] (fn [x] (apply * (repeat n x))))` 

它這樣使用

((power 2) 16) 

時,我可以替代2與其它電力工作得很好,但我想提出一個功能只是爲了正方形,立方體等等。什麼是最好的方式來做到這一點?我一直在REPL中擺弄它,但到目前爲止還沒有運氣。

+0

我沒有得到你的問題。你想創建功能的集合:正方形,立方體等? –

+0

是的。我寧願採用(power 2)語法,並用power2,power3(立方體)替換它,等等。當然,有一個數學庫,在生產代碼中,我不會這樣做,但我試圖將原始函數映射爲它將如何接收它的參數,並且在REPL中試用這個函數非常有幫助。 – octopusgrabbus

回答

7

爲此,使用宏完全圍繞他的問題,即「我有一個生成閉包的函數,我如何給這些閉包名稱?」簡單的解決辦法是:

(letfn [(power [n] 
      (fn [x] 
      (apply * (repeat n x))))] 
    (def square (power 2)) 
    (def cube (power 3))) 

如果你真的真的恨重複defpower了幾下,然後才把是時候涉足宏。但是,即使是最簡單的宏,您花費的精力也將被浪費,除非您定義的功能至少達到十分之一的功率,而功能卻很簡單。

+0

是的,但他的問題似乎錯誤地表達出來,我不確定這很簡單。 「等等」部分告訴我他正在尋找的不僅僅是他實際要求的東西?我向你提出了嚴格的要求。 –

+0

(def square(power 2))就是我在找的東西,但有一個宏觀答案也很有幫助。就我個人而言,我會使用(電源2),但想知道如何縮短它。 – octopusgrabbus

1

不太確定這是您要搜索的內容,但可能是宏模板。這是我會怎麼寫代碼:

(use 'clojure.template) 

(do-template [name n] 
    (defn name [x] (apply * (repeat n x))) 
    square 2 
    cube 3) 

user> (cube 3) 
;=> 27 

對於更復雜的類型相似的任務,你可以寫一個宏包do-template到其參數進行一些改造,如:

(defmacro def-powers-of [& ns] 
    (let [->name #(->> % (str "power") symbol)] 
    `(do-template [~'name ~'n] 
     (defn ~'name [~'x] (apply * (repeat ~'n ~'x))) 
     [email protected](->> ns 
       (map #(vector (->name %) %)) 
       flatten)))) 

(def-powers-of 2 3 4 5) 

user> (power3 3) 
;=> 27 

user> (power5 3) 
;=> 243 

PS:如果你剛剛開始使用Clojure,那麼這個宏可能看起來很尷尬,不要因爲它而放棄! ;-)

+0

謝謝。這是一個很好的答案。很多我學習Clojure的問題讓我的眼睛籠罩在語法上。我用越來越少的小屁股來製作不一定會用的東西,我就越瞭解東西。 – octopusgrabbus