Importantly, I'm *not* working symbolically. The specific pattern I'm trying to illustrate:
((eval (with-meta (fn [] 5) nil))) ;; works, note `nil` meta
(eval (list (with-meta (fn [] 5) nil))) ;; likewise
((eval (with-meta (fn [] 5) {}))) ;; works, note `{}' meta
(eval (list (with-meta (fn [] 5) {}))) ;; fails, no matching ctor found for class clojure.lang.AFunction$1
I encountered this working on somewhat `meta`-heavy function generators for a system where functions can opt-in to certain behaviors with their meta, but don't necessarily have meta, and are not necessarily symbolic/`def`ined. This works a treat, except when trying to `eval` it or embedding it in a backtick template.
This required me to use my little `val->expr` helper, which also works a treat. Clojure knows how to evaluate function values, just as long as they don't have meta, but if a function-expr `f` has meta `m`, Clojure also knows how to evaluate `(with-meta (with-meta f nil) (meta f))
As to your last point, I agree entirely and that's kinda what I was trying to say. Manually doing the `(with-meta (with-meta f nil) (meta f))` trick every time I embed a function in case it has any metadata feels like handling Clojure implementation details that I shouldn't generally be worried about. Thus my question.
My more general question was, if this is possible, why not generalise it to other function-values (which, regardless of metadata, would be AFunctions and have no constructors) by implementing some fallback mechanism where, if a value (e.g. an AFunction) has (a) no constructor and (b) meta with some special key containing a function which takes the value and returns a Clojure expression-to-be-evaluated, e.g. the meta case, and likewise for `every-pred` and `complement` etc. to eval as a list with their name and args.
I'll post better/more concrete examples tomorrow, but for today I noticed another maybe-related strange-behavior/bug:
(def f1 (eval +))
(def f2 (eval (list `with-meta + nil)))
(def f3 (eval (list `identity +)))
(def f4 (eval (list `var-get (list `var `+))))
All of these evaluate to `#function[clojure.core/+]`. However:
(= f1 f2) ;=> true
(= f1 f4) ;=> true
;; however
(= f1 f3) ;=> false
So in summary:
;; works
((eval (with-meta (fn []) {})))
;; throws error (but shouldn't?)
(eval (list (with-meta (fn []) {})))
;; true
(= + (eval +))
;; not true (but should be?)
(= + (eval (list `identity +)))
Not really sure where to proceed to with these. If these were solved by the corelib, I as a user wouldn't need to be doing this.
A couple questions:
a) Where can I read more about `#=`? I couldn't find documentation for it
b) Why does `(eval (list `identity +))` return a different value to `+`? At the very least it feels unintuitive that they wouldn't be `=` even if not `identical?`, but why wouldn't they be identical?