behavior of var function - clojure

I have two somewhat related problems, shown by the following:
user=> (if (symbol? 5) (meta (var 5)) 5)
CompilerException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:6)
user=> (defn dometa [x] (if (symbol? x) (meta (var x)) x))
CompilerException java.lang.RuntimeException: Unable to resolve var: x in this context, compiling:(NO_SOURCE_PATH:7)
user=>
In the first case, since 5 is not a symbol I would not expect (meta (var 5)) to be evaluated, but it is (or at least that's the way it seems to me).
In the second case, if I want to place the first expression in a function, and parameterize the value being tested, the (var ...) function no longer works.

The Var object is looked up at compile time. For the behaviour I'm inferring from your examples, you should use find-var.
user=> (if (symbol? 5) (meta (find-var 5)) 5)
5
user=> (defn dometa [x] (if (symbol? x) (meta (find-var x)) x))
#'user/dometa

Related

Why does adding metadata to a function definition work differently than other forms, in Clojure?

Why does this fail:
(eval (with-meta '(fn [] 0) {:stack (gensym "overflow")}))
; Syntax error compiling at (REPL:1:1).
; Unable to resolve symbol: overflow210 in this context
when none of the following fail?
(eval (with-meta '(do [] 0) {:stack (gensym "overflow")}))
; 0
(eval (with-meta '(let [] 0) {:stack (gensym "overflow")}))
; 0
(eval (with-meta '(if true 0 1) {:stack (gensym "overflow")}))
; 0
(eval (with-meta '(println "hello") {:stack (gensym "overflow")}))
; hello
; nil
The examples above are my attempt to find a minimal, reproducible example. I ran into this question when working on a macro, with a simplified example here:
(defmacro my-macro []
(with-meta '(fn [] 0) {:stack (gensym "overflow")}))
(my-macro)
; Syntax error compiling at (REPL:1:1).
; Unable to resolve symbol: overflow156 in this context
while attempting to follow the model explained in this post on testing Clojure macros.
Great question! This was fun to dig into.
It's helpful to first start by trying to set the metadata map to something that works, and retrieve it in each of your examples:
(meta (eval (with-meta '(fn [] 0) {:ten 10})))
;;=> {:ten 10}
(meta (eval (with-meta '(do [] 0) {:ten 10})))
;;=> nil
(meta (eval (with-meta '(let [] 0) {:ten 10})))
;;=> nil
(meta (eval (with-meta '(if true 0 1) {:ten 10})))
;;=> nil
(meta (eval (with-meta '(println "hello") {:ten 10})))
;; printed: hello
;;=> nil
Hopefully this gives you some idea of what's happening here: the metadata isn't returned as part of the value of the non-fn forms, so it's not evaluated. We can test this hypothesis with another value that uses its metadata, like a vector:
(meta (eval (with-meta '[1] {:ten 10})))
;;=> {:ten 10}
but with a gensym:
(eval (with-meta '[1] {:stack (gensym "overflow")}))
;;=> Syntax error compiling at (tmp:localhost:35479(clj)*:25:7).
;;=> Unable to resolve symbol: overflow6261 in this context
You can see where this is emitted in the Clojure compiler, and searching for new MetaExpr will show you the other places where metadata evaluation is emitted (I could see vectors, maps, sets, functions, and reify).
tl,dr: Clojure evaluates the metadata for function forms because it attaches the evaluated metadata to the resulting function. This is also true of the data literals supported in Clojure's syntax. Any other metadata on forms is stripped away by compilation, so it doesn't get evaluated and thus doesn't cause symbol resolution errors.
The problem is your usage of gensym, not the metadata. Observe:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(dotest
(binding [*print-meta* true]
(let [
fn-code-plain '(fn [] 42)
fn-code-meta (with-meta '(fn [] 42) {:alpha true})
fn-code-sym-meta (with-meta '(fn [] 42) {:alpha (gensym "dummy")})
]
(prn fn-code-plain)
(prn fn-code-meta)
\
(prn (eval fn-code-plain))
(prn (eval fn-code-meta))
(newline)
(prn fn-code-sym-meta)
(throws? (eval fn-code-sym-meta))
)
))
with result:
^{:line 7, :column 27} (fn [] 42)
^{:alpha true} (fn [] 42)
#object[user$eval19866$fn__19867 0xac891b5 "user$eval19866$fn__19867#ac891b5"]
^{:alpha true} #object[user$eval19870$fn__19871 0x2d1ab7e0 "user$eval19870$fn__19871#2d1ab7e0"]
^{:alpha dummy19865} (fn [] 42)
The problem is that eval sees the symbol dummy19865 and tries to resolve it. The fact that it was created by gensym is irrelevant. No problem with a keyword:
fn-code-kw-meta (with-meta '(fn [] 42) {:alpha :dummy-42})
<snip>
(prn fn-code-kw-meta)
(prn (eval fn-code-kw-meta))
producing:
^{:alpha :dummy-42} (fn [] 42)
^{:alpha :dummy-42} #object[user$eval19953$fn__19954 0x13253ac7 "user$eval19953$fn__19954#13253ac7"]
or a symbol that is defined:
(def mysym "Forty-Two!")
<snip>
fn-code-mysym-meta (with-meta '(fn [] 42) {:alpha mysym})
<snip>
(prn fn-code-mysym-meta)
(prn (eval fn-code-mysym-meta))
with result:
^{:alpha "Forty-Two!"} (fn [] 42)
^{:alpha "Forty-Two!"} #object[user$eval20082$fn__20083 0x24a63de5 "user$eval20082$fn__20083#24a63de5"]
Summary:
You have demonstrated that eval only attempts symbol resolution of metadata for the fn form, but not other special forms like do, let, if, or with pre-existing functions such as println. If you wish to explore further, you should probably inquire at the Clojure email list:
clojure#googlegroups.com
The above code is based on this template project.

What is the "name?" argument in Clojure's fn?

I am reading the book "Getting Clojure" by Russ Olsen. In chapter 8, "Def, Symbols, and Vars", there is the following function definition:
(def second (fn second [x] (first (next x))))
^^^^^^
My question is regarding the underlined second, which comes second.
At first, I thought this syntax is wrong as anonymous functions don't need a name. But as it turnes out, this syntax is correct.
Usage: (fn name? [params*] exprs*)
(fn name? ([params*] exprs*) +)
I tried comparing the following two function calls.
user> (fn second [x] (first (rest x)))
#function[user/eval5642/second--5643]
user> (fn [x] (first (rest x)))
#function[user/eval5646/fn-5647]
Besides the name of the function, there does not seem to be a difference.
Why would there be a name? argument to fn?
You can use it when creating multiple arities:
(fn second
([x] (second x 1))
([x y] (+ x y)))
or if you need to make a recursive call:
(fn second [x] (when (pos? x)
(println x)
(second (dec x))))
There are two main usages:
recursive functions (you now know the name)
user=> ((fn foo [x] (when (pos? x) (println x) (foo (dec x)))) 3)
3
2
1
nil
better stacktraces (the name will give you a better hint, where things went wrong)
user=> (map (fn bar [x] (inc x)) ["a"])
Error printing return value (ClassCastException) at clojure.lang.Numbers/inc (Numbers.java:137).
java.lang.String cannot be cast to java.lang.Number
user=> (pst)
ClassCastException java.lang.String cannot be cast to java.lang.Number
clojure.lang.Numbers.inc (Numbers.java:137)
user/eval8020/bar--8021 (NO_SOURCE_FILE:1)
clojure.core/map/fn--5866 (core.clj:2753)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
clojure.lang.RT.seq (RT.java:535)
clojure.core/seq--5402 (core.clj:137)
clojure.core/seq--5402 (core.clj:137)
puget.printer.PrettyPrinter (printer.clj:529)
puget.printer/iseq-handler--1663 (printer.clj:314)
puget.printer/iseq-handler--1663 (printer.clj:312)
puget.printer/format-doc* (printer.clj:223)
(note user/eval8020/bar--8021)

Why applying seq on a LazySeq returns ChunkedCons?

(class (range 10))
;=> clojure.lang.LazySeq
(class (seq (range 10))
;=> clojure.lang.ChunkedCons
From my understanding, LazySeq is already an sequence, since:
(seq? (range 10))
;=> true
I guess I have an answer.
That's because using seq enforces the evaluation of the first element of LazySeq. Because seq returns nil when the collection & sequence is empty, it has to eval the element to decide that.
That's the exactly reason why rest is lazier than next, because (next s) is just (seq (rest s)).
To expand upon your answer (and because comments don't support new lines):
user=> (def r (range 10))
#'user/r
user=> (realized? r)
false
user=> (class r)
clojure.lang.LazySeq
user=> (def r2 (rest r))
#'user/r2
user=> (realized? r2)
ClassCastException clojure.lang.ChunkedCons cannot be cast to clojure.lang.IPending clojure.core/realized? (core.clj:6607)
user=> (class r2)
clojure.lang.ChunkedCons
user=> (realized? r)
true

Function arguments multiple types

I am trying to delay various calculations. I have functions of the following form,
(defn a-fn [a b]
(let [a (if (fn? a)
a
#(identity a))
b (if (fn? b)
b
#(identity b))]
(+ (a) (b))))
this allows me to pass a-fn, a value or a function that returns the value,
(a-fn 1 2)
(defn x [] 1)
(defn y [] 2)
(a-fn x y)
(a-fn x 2)
what I do is build a list of functions (like the one above) to operate on some data, fns may use other fns to retrieve their arguments or in some cases things don't change and they are assigned values as arguments. I was wondering is there a better way to achive this kind of behavior?
You can use delay and force:
user=> (defn a-fn [a b] (+ (force a) (force b)))
#'user/a-fn
user=> (a-fn 1 2)
3
user=> (def x (delay 1))
#'user/x
user=> (def y (delay 2))
#'user/y
user=> (a-fn x y)
3
user=> (a-fn x 2)
3
If you try something like (delay (prn :hello) 1) to test when the computation is done, note that printing the Delay object forces it; so (def x (delay ...)) is safe, but typing a plain (delay ...) in the REPL prompt is not.
There might be a more elegant way to do what you want, but here's at least a more generic version of it:
(defn delayed [reducer & fs]
(apply reducer (for [f fs] (if (fn? f) (f) f))))
(def a-fn (partial delayed +))
So delayed takes an arbitrary function and a list of function/values. If expands all the args and then applies the function to them. Then we use partial to define your a-fn using +:
user=> (a-fn 1 2)
3
user=> (a-fn (constantly 1) 2)
3
user=> (a-fn (constantly 1) 2 4)
7
Alternatively, it might make sense for delayed to return a function rather than using partial. Note sure which is better.
A better name than "delayed" is welcome :)

Single predicate to test for "self-evaluating" atoms in Clojure

At the home site of Clojure, there is the following statement:
Strings, numbers, characters, true,
false, nil and keywords evaluate to
themselves.
Is there a single combined predicate that tests for any of these, combining string?, number?, char?, true?, false?, nil?, and keyword?. Should I just use (complement symbol?)?
Maybe I'm missing something, but you could use the following to test for any of those conditions and return true if one is true:
(defn self-eval?
[x]
(or (string? x)
(number? x)
(char? x)
(keyword? x)
(true? x)
(false? x)
(nil? x)))
It's easy enough to write a macro that asks "does the given expression evaluate to itself". In fact this is a good example of tasks that can only be done with a macro because they need to see the argument both evaluated and unevaluated.
(defmacro selfp [a] `(= ~a (quote ~a)))
#'user/selfp
user> (selfp 1)
true
user> (selfp +)
false
user> (selfp [1 2])
true
user> (selfp '(+ 1 2 3))
false
While strings, numbers, characters, keywords, and the booleans are all self-evaluating, other things such as [1 2] are as well,so this may not be a useful test in general.
Another option is to create a function that uses a map:
(defn myclassifier? [x]
(let [types-I-care-about #{java.lang.Sring ...}]
(if (types-I-care-about (type x))
true
false)))
Another option which may have better performance is to use java's dynamism:
(extend-type Object
IMyClassifier
(myclassifier? [x]
(let [c (.getClass x)]
(if (types-I-care-about (type c))
(do
(extend-type (.getClass x)
IMyClassifier
(myclassifier? [x] true))
true)
false))))
where types-I-care-about is a set of types you care about.