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
-~----------~----~----~----~------~----~------~--~---

Reply via email to