On 1/25/12 2:25 AM, Tassilo Horn wrote:
Hi again,
I think, I got it. I wrote a little helper function to print the
metadata of a form:
--8<---------------cut here---------------start------------->8---
(use 'clojure.walk)
(defn print-meta
([form level]
(prewalk
(fn [x]
(when-let [m (meta x)]
(println "Level" level ":" x "=>" m)
(print-meta m (inc level)))
x)
form))
([form]
(print-meta form 0)))
--8<---------------cut here---------------end--------------->8---
Now see what happens:
--8<---------------cut here---------------start------------->8---
user> (print-meta (macroexpand-all '(def b (fn ^foo [^bar x] ^baz x))))
Level 0 : x => {:tag bar}
Level 0 : x => {:tag baz}
(def b (fn* ([x] x)))
user> (print-meta (macroexpand-all '(defn b ^foo [^bar x] ^baz x)))
Level 0 : b => {:arglists (quote ([x]))}
Level 1 : [x] => {:tag foo}
Level 1 : x => {:tag bar}
Level 0 : x => {:tag bar}
Level 0 : x => {:tag baz}
(def b (fn* ([x] x)))
--8<---------------cut here---------------end--------------->8---
So the return type metadata is actually added to the :arglist metadata
contents, so it's actually meta-metadata. What you seem to have to do
is to make sure the :arglists metadata is there and reflects the type
hints on the actual function:
--8<---------------cut here---------------start------------->8---
user> (def ^{:arglists '(^double [^double x])}
with-def (fn ^double [^double x] (+ x 0.5)))
#'user/with-def
user> (pt (with-def 1))
:double
--8<---------------cut here---------------end--------------->8---
Well, that's not really obvious. Maybe `def' could do a better job here
and build up a correct :arglists metadata value somehow...
Bye,
Tassilo
Hi Tassilo,
Thanks for doing the detective work! I still have some questions
though... In my example I used def because I was able to reproduce the
bug with def and it was the easiest way to show it. However, in practice
these anonymous functions won't be bound to a root var (hence the
anonymous part :) ). I would like to be able to write code like this:
(map-doubles (fn ^double [^double x] (+ x 0.5)) array)
I don't seem to be able to do that since the type hints are not put into
effect without a var (it would seem):
(pt ((fn ^double [^double x] (+ x 0.5)) 1.0)) ; => :object
Not just put into effect, but not even stored on the function (as far as
I can tell):
(meta (fn ^double [^double x] (+ x 0.5))) ; => nil
I've tried adding the appropriate metadata onto the function (I'm
stealing the metadata from our earlier with-defn):
(meta (with-meta (fn ^double [^double x] (+ x 0.5)) (select-keys (meta
#'with-defn) [:arglists]))) ; => {:arglists ([x])}
I can verify that the arglist is tagged with the primitive just like it
is with the var #'with-defn:
(defn arglist-tag [var]
(-> var meta :arglists first meta :tag))
(arglist-tag #'with-defn) ; => double
(arglist-tag (with-meta (fn ^double [^double x] (+ x 0.5)) (select-keys
(meta #'with-defn) [:arglists])))A ; => double
Sadly, even with the arglist meta-metadata boxing is still occurring:
(pt ((with-meta (fn ^double [^double x] (+ x 0.5)) (select-keys (meta
#'with-defn) [:arglists])) 1.0)) ; => object
It is probably obvious that this would not work to someone who
understands clojure's implementation, but to me this was a surprise.
From this I gather that type hints on vars are what clojure uses and
type hints on the actual functions are ignored.
Am I missing something, or does the new primitive support only apply to
bound functions?
-Ben
--
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
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en