This is another case of function-object evaluation acting hinky, actually.

Specifically, (eval (id 7)) is evaluating a list of (id 7), not ('id
7). As near as I can figure out, rather than embed the function object
reference into the code OR complain, it is creating a new instance of
its class with newInstance, more or less in the manner I suggested in
another thread recently -- the failure with closures happening because
it doesn't check for closures and closures don't have a public
no-argument constructor, so need special handling (and preservation of
the arguments they were constructed with -- the closed-over values).

A longer-term fix might be to make instances of the function
superclass generated by (fn [foo] bar) (but not all IFns!) compare
equal if their exact classes are equal and, in the case that they are
closures, the closed-over values compare equal. This doesn't break the
expected semantics that functions that behave differently should
compare UNequal, but allows functions to be represented as constructor
calls to their classes and then reconstructed without breaking
equality.

In particular, we don't need to use eval to get hinky function
equality semantics already:

user=> (defn fn-maker1 [] (fn [] 3))
#'user/fn-maker1
user=> (= (fn-maker1) (fn-maker1))
false
user=> (defn fn-maker2 [x] (fn [] x))
#'user/fn-maker2
user=> (= (fn-maker2 3) (fn-maker2 3))
false
user=> (= (fn-maker2 3) (fn-maker2 4))
false
user=> (defn fn-maker3 [x y] (fn [z] (+ (* z x) y)))
#'user/fn-maker3
user=> (= (fn-maker3 1 2) (fn-maker3 1 2))
false
user=> (= (fn-maker3 1 2) (fn-maker3 2 1))
false

Ideally, the results would be this instead:

user=> (defn fn-maker1 [] (fn [] 3))
#'user/fn-maker1
user=> (= (fn-maker1) (fn-maker1))
true ; conceptually identical functions
user=> (defn fn-maker2 [x] (fn [] x))
#'user/fn-maker2
user=> (= (fn-maker2 3) (fn-maker2 3))
true ; conceptually identical functions
user=> (= (fn-maker2 3) (fn-maker2 4))
false ; genuinely not the same
user=> (defn fn-maker3 [x y] (fn [z] (+ (* z x) y)))
#'user/fn-maker3
user=> (= (fn-maker3 1 2) (fn-maker3 1 2))
true ; conceptually identical functions
user=> (= (fn-maker3 1 2) (fn-maker3 2 1))
false ; not the same:
user=> ((fn-maker3 1 2) 10)
12
user=> ((fn-maker3 2 1) 10)
21

Now, fn-maker3 could have produced (fn [z] (+ x y z)) in which the
roles of x and y are symmetrical, but I don't think it reasonable to
expect the compiler to detect every situation in which distinct
closed-over values give identically-behaved functions (in fact that's
probably equivalent to the halting problem) so I'd consider it
reasonable for it to consider closures unequal if they have distinct
sequences of closed-over values (and I say "sequences" here because as
fn-maker3 shows they aren't generally interchangeable; the constructor
for fn-maker3's closure's class will have some particular order it
takes them in and as sequences in that order they'd have to be equal
for two fn-maker3 results to be treated as equal here).

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

Reply via email to