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! ;-)
精彩评论