开发者

How To Define Function From Closure

This question is related to one I asked recently.

开发者_开发百科If I rewrite (fn [n] (fn [x] (apply * (repeat n x)))) as

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

it works just fine when used like this

((power 2) 16)

I can substitute 2 with another power, but I'd like to make a function just for squares, cubed, and so on. What is the best way to do that? I've been fiddling with it in the REPL, but no luck so far.


Using a macro for this goes entirely around his question, which was "I have a function that generates closures, how do I give those closures names?" The simple solution is:

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

If you really truly hate repeating def and power a few times, then and only then is it time to get macros involved. But the amount of effort you'll spend on even the simplest macro will be wasted unless you're defining functions up to at least the tenth power, compared to the simplicity of doing it with functions.


Not quite sure if this is what you're searching for, but macro templates might be it. Here's how I would write your code:

(use 'clojure.template)

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

user> (cube 3)
;=> 27

For more complex type of similar tasks, you could write a macro that wrap do-template to perform some transformation on its arguments, e.g.:

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

(def-powers-of 2 3 4 5)

user> (power3 3)
;=> 27

user> (power5 3)
;=> 243

P.S.: That macro might look awkward if you're just starting with Clojure though, don't give up because of it! ;-)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜