On Wed, Aug 19, 2009 at 10:03 AM, Achim Passen <[email protected]>wrote:

> Beware! This snippet relies on unexposed details of clojure's current
> implementation. It might stop working tomorrow, so it's definitely not
> intended for production use, but it might help with debbuging/exploring.


Meanwhile, for declared functions this works:

(map #(if (contains? (set %) '&) [:more (- (count %) 2)] (count %))
(:arglists ^#'foo))

giving results like:

(0 2 5 [:more 7])

(in this case for (defn foo ([] nil) ([glorb fuzzle] nil) ([x y z w u] x)
([a b c d e f g & more] more)))

Add this:

(defn accepts-arity [arities arity]
  (or
    (contains? (set arities) arity)
    (and (vector? (last arities)) (>= arity (second (last arities))))))

and you can check if the function accepts a particular arity. (This expects
"arities" in the format output by my map expression. In particular, a list
of numerical arities and possibly a [:more n] entry, which must be a vector
and must be the last item in the list if present, and n must be the number
of required parameters for the "& more" overload.)

Wrap it all up with two macros:

(defmacro fn-arities [fn-name]
  `(map (fn [x#] (if (contains? (set x#) '&) [:more (- (count x#) 2)] (count
x#))) (:arglists ^#'~fn-name)))

(defmacro fn-accepts-arity [fn-name arity]
  `(accepts-arity (fn-arities ~fn-name) ~arity))

user=> (fn-accepts-arity foo 8)
true
user=> (fn-accepts-arity foo 6)
false
user=> (fn-accepts-arity reduce 2)
true
user=> (fn-accepts-arity reduce 3)
true
user=> (fn-accepts-arity reduce 4)
false
user=> (fn-arities map)
(2 3 4 [:more 4])

Works for macros, too:

user=> (fn-arities fn-arities)
(1)
user=> (fn-arities fn-accepts-arity)
(2)

But, as noted, only works with a name of a declared fn or macro:

user=> (fn-arities #(+ 3 %))
#<CompilerException java.lang.ClassCastException: clojure.lang.Cons cannot
be cast to clojure.lang.Symbol (NO_SOURCE_FILE:110)>

(One thing odd about that:

user=> (class '#(+ 3 %))
clojure.lang.PersistentList

not Cons. Hmm.)

It also doesn't work with local, named functions, either using let or using
letfn, even if (fn name [args] body) is used and not (fn [args] body):

user=> (let [x (fn [a] (+ 3 a))] (fn-arities x))
#<CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:117)>
user=> (let [x (fn x [a] (+ 3 a))] (fn-arities x))
#<CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:118)>
user=> (letfn [(x [a] (+ 3 a))] (fn-arities x))
#<CompilerException java.lang.Exception: Unable to resolve var: x in this
context (NO_SOURCE_FILE:119)>

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your 
first post.
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