I would like to suggest to improve currying. Right now Clojure already comes with a nice way to do something that is nearly as good as currying, but still not fully. In a very functional programming style this makes sense to have good currying support. Here is my proposal for extending the #(...) notation, and I would like to give some examples too:
1. Leave out all arguments after the last specific one was given. This means we need to rewrite the curry notation into one that uses apply. Examples: #(< 5) instead of #(< 5 %) or #(< 5 %&) #(< 5) ==> (fn [& args] (apply + 5 args)) If foo has arity 11: #(foo 10 20) instead of #(foo 10 20 %&) or, for those insisting on correct arity even #(foo 10 20 %1 %2 %3 %4 %5 %6 %7 %8 %9) #(foo 10 20) ==> (fn [& args] (apply foo 10 20 args)) 2. If the value of an argument is not important use an underscore. This will free us of uses of %1, %2, ... Examples: Create a function that will produce blue colors: #(rgb _ _ 255) instead of #(rgb %1 %2 255) #(rgb _ _ 255) ==> (fn [arg1 arg2 & args] (apply rgb arg1 arg2 255 args)) Making use of point 1., now for creating green objects: #(rgb _ 250) instead of #(rgb %1 250 %2) #(rgb _ 250) ==> (fn [arg1 & args] (apply rgb arg1 250 args)) 3. Let's keep the possibility to list specific arguments as %1, %2, ... So we still want to have a function to square its argument: #(* %1 %1) ==> (fn [arg1 & args] (apply * arg1 arg1 args)) 4. Possibly allowing nested curries, where only the outer one is allowed to list specific arguments %1, %2, %3, ... All inner ones may only use the underscore syntax: #(map #(+ 3) %1 %1) ==> (fn [arg1 & args] (apply map (fn [& args] (apply + 3 args)) arg1 arg1)) As I see it the reader macro #(...) is right now implemented in Assemb... in Java. So I can't give a patch for that, but instead I hacked up this code fast, and it basically wraps the idea into a macro: (defn replace-placeholders [body] ((fn [args new-body [f & r :as b]] (if (not b) [(seq args) (seq new-body)] (cond (= f '_) (let [gensym (gensym)] (recur (conj args gensym) (conj new-body gensym) r)) :default (recur args (conj new-body f) r)))) [] [] body)) (defn applyify [args body] `(fn [EMAIL PROTECTED] & args#] (apply [EMAIL PROTECTED] args#))) (defmacro § [& body] (let [[args body] (replace-placeholders body)] (applyify args body))) user> (filter (§ < _ 9) (range 20)) (0 1 2 3 4 5 6 7 8) user> (map (§ * 3) (range 10)) (0 3 6 9 12 15 18 21 24 27) I couldn't name the macro # as the reader would obviously try to consume it first. So, if implemented as a reader macro we could say §(< _ 9) or §(* 3) and such. This version of replace-placeholders still misses the numbered args %1, %2, .. as the reader would also steal those from me. In the end the #(..) macro would do it, instead of §. I would like to hear/read your opinions about support for currying and extending the #() macro. One thing I see as possibly critical is that my suggestion for always using apply could potentially slow down code. apply would have to do some extra work that is not needed when a function is called directly. How true is that, Rich? I imagine situations where we (map #(* 5) collection-of-10-million-numbers) and get the apply runtime hit 10 mio times. One way to improve this a little is to have all functions from the standard Clojure lib that take a fixed number of args and treat them differently, and compile into code that makes no use of apply. In such a case the 11-ary function foo would give us for #(foo _ 10 20) ==> (fn [a1 a2 a3 a4 a5 a6 a7 a8 a9] (foo a1 10 20 a2 a3 a4 a5 a6 a7 a8 a9)) ; a direct call This could be done only for the functions that come with Clojure as those are guaranteed to always do the same and can't be over- written by the user. (defn + ...) is not possible ==> java.lang.Exception: Name conflict, can't def + because namespace: user refers to:#=(var clojure/+) So, all functions written by the user must be called via apply if we curry arguments away, even if the user provided function has a fixed number of args, as the user could always exchange his old function with a new one. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---