(let [docstring (if (string? (first options))
(first options)
nil)
options (if (string? (first options))
(next options)
options)
m (if (map? (first options))
(first options)
{})
options (if (map? (first options))
(next options)
options)
dispatch-fn (first options)
options (next options)
m (assoc m :tag 'clojure.lang.MultiFn)
m (if docstring
(assoc m :doc docstring)
m)
m (if (meta mm-name)
(conj (meta mm-name) m)
m)]
Is it worth capturing this common idiom in a helper function, e.g. pop-
optional-args:
(defn pop-optional-args
[preds args]
(if (seq preds)
(if ((first preds) (first args))
(cons (first args) (pop-optional-args (rest preds) (rest args)))
(cons nil (pop-optional-args (rest preds) args)))
(list args)))
The above let form would then be:
(let [[docstring m dispatch-fn options] (pop-optional-args [string?
map? identity] options)
m (assoc m :tag 'clojure.lang.MultiFn)
m (if docstring
(assoc m :doc docstring)
m)
m (if (meta mm-name)
(conj (meta mm-name) m)
m)]
Worth doing? If so, how could it be better?
Stu
It's tough to guess as to the general applicability of this. One thing
for sure, it's not really about args, more like a 'take-' or 'split-'
variant. Finding a good name might point the way towards a general
utility.
Rich
[name doc-string? attr-map? [params*] body]
Each of this expects a different type of object right?
name - clojure.lang.Symbol
doc-string? - java.lang.String
attr-map? clojure.lang.IPeristentMap
params* - IPeristentVector
body - IPerisistentSeq
What if we used c.c.seq-utils/group-by with class? This would create
hash map with the appropriate values options in it. From there it's a
simple matter of processing a map. I think that the aritiy overloaded
version of defn is easy enough to detect to. Would that do the trick?
Sean
There's clojure.contrib.def/name-with-attributes for the frequent case
of a def-ing macro that takes an optional docstring and/or attribute
map:
(defn name-with-attributes
"To be used in macro definitions.
Handles optional docstrings and attribute maps for a name to be
defined
in a list of macro arguments. If the first macro argument is a
string,
it is added as a docstring to name and removed from the macro
argument
list. If afterwards the first macro argument is a map, its entries
are
added to the name's metadata map and the map is removed from the
macro argument list. The return value is a vector containing the
name
with its extended metadata map and the list of unprocessed macro
arguments."
[name macro-args]
...)
Konrad.
(defn aaa
(defn bla
([aaa bbb ccc] ....)
([bbb cc] (bla 0 bbb cc)))
etc.
That's the preferred approach for me too, but it doesn't work for
functions that take a variable number of arguments.
Konrad.