If I do this:
(eval (let [f (fn [& _] 10)]
`(~f nil)))
It returns 10 as expected.
Although if I do this:
(eval (let [f (constantly 10)]
`(~f nil)))
It throws an exception:
IllegalArgumentException No matching ctor found for
class clojure.core$constantly$fn__... clojure.lang.Reflector.invokeConstructor
Since both are equivalent why is the code with constantly not working?
This question has two answers, to really get it.
First, to clarify why your eval form is not giving you the expected result in the second case, note that f has been assigned to be equal to the function (fn [& _] 10). This means when that form is evaluated, the function object is again evaluated--probably not what you had in mind.
tl;dr: f is evaluted when it is bound, and again (with ill-defined results) when the form you create is eval'd.
The reason why one (the anonymous function) works, while the other fails means we have to look at some of the internals of the evaluation process.
When Clojure evaluates an object expression (like the expression formed by a function object), it uses the following method, in clojure.lang.Compiler$ObjExpr
public Object eval() {
if(isDeftype())
return null;
try
{
return getCompiledClass().newInstance();
}
catch(Exception e)
{
throw Util.sneakyThrow(e);
}
}
Try this at the REPL:
Start with an anonymous function:
user=> (fn [& _] 10)
#<user$eval141$fn__142 user$eval141$fn__142#2b2a5dd1>
user=> (.getClass *1)
user$eval141$fn__142
user=> (.newInstance *1)
#<user$eval141$fn__142 user$eval141$fn__142#ee7a10e> ; different instance
user=> (*1)
10
Note that newInstance on Class calls that class' nullary constructor -- one that takes no arguments.
Now try a function that closes over some values
user=> (let [x 10] #(+ x 1))
#<user$eval151$fn__152 user$eval151$fn__152#3a565388>
user=> (.getClass *1)
user$eval151$fn__152
user=> (.newInstance *1)
InstantiationException user$eval151$fn__152 [...]
Since the upvalues of a closure are set at construction, this kind of function class has no nullary constructor, and making a new one with no context fails.
Finally, look at the source of constantly
user=> (source constantly)
(defn constantly
"Returns a function that takes any number of arguments and returns x."
{:added "1.0"
:static true}
[x] (fn [& args] x))
The function returned by constantly closes over x so the compiler won't be able to eval this kind of function.
tl;dr (again): Functions with no upvalues can be evaluated in this way and produce a new instance of the same function. Functions with upvalues can't be evaluated like this.
Related
I have a small function used for debugging:
(set! *warn-on-reflection* true)
(defn debug [x] (doto x (->> println :>)))
When I call my function in a loop, I get the following reflection warning:
(loop [i 5] (when (pos? i) (recur (debug (dec i)))))
form-init14269737395101875093.clj:1 recur arg for primitive local: i is not matching primitive, had: Object, needed: long
Auto-boxing loop arg: i
I want to solve the reflection warning. How can I make my function "inherit" the type information from the parameter without explicitly specifying it or replacing it with a macro?
Here is a way that works:
(loop [i (Integer. 5)]
(when (pos? i)
(recur (debug (dec i)))))
with a warning-free result:
lein test tst.demo.core
4
3
2
1
0
It looks like using just plain 5 causes the compiler to use a primitive, which can't be type hinted. Explicitly creating an Integer object sidesteps the problem. I also tried (int 5) which didn't work.
Is there a reason you want to turn on reflection warnings? I normally never use them, especially for debugging.
Update
Note that if you wrap the code in a function like so:
(defn stuff
[arg]
(loop [i arg]
(when (pos? i)
(recur (debug (dec i))))))
there is no problem calling (stuff 5) since function args must always be passed as objects (via autoboxing if necessary).
the problem is that the return type of debug can't be deduced.
this is usually solved with type hints
in your case the following should do the trick:
(defn debug ^long [x] (doto x (->> println :>)))
user> (loop [i 5] (when (pos? i) (recur (debug (dec i)))))
4
3
2
1
0
nil
If, for whatever the reason, you do not want to use a macro, you may want to have a look at definline which seems to preserve type information:
(definline debug2 [x] (doto x (->> println :>)))
The call below, for instance, does not result in a reflection warning:
(.add (debug2 (ArrayList.)) 5)
My initial thought would have been to use a Java class with overloaded methods to achieve something along these lines, of which one method would take a generic argument T and return a T. In addition to this generic method, you would have had to overload that method for the few primitive types because generics only work with boxed values AFAIK. You could then reuse the class below for your debugging purposes:
import clojure.lang.IFn;
public class PassThrough {
private IFn _fn;
public PassThrough(IFn fn) {
_fn = fn;
}
public <T> T invoke(T x) {
_fn.invoke(x);
return x;
}
public long invoke(long x) {
_fn.invoke(x);
return x;
}
public double invoke(double x) {
_fn.invoke(x);
return x;
}
}
This will not work for reference types, though, because of type erasure. So if I would do something like this, I would still get a warning:
(defn debug [x] (doto x (->> println :>)))
(def pt-debug (PassThrough. debug))
(.add (.invoke ^PassThrough pt-debug (ArrayList.)) 9) ;; <-- Reflection warning here when calling .add
Currently I have some code like this:
(defn compute-issue [some args] (or (age-issue some args) (name-issue some args)))
More issue types are coming.
Is there something like this:
(defn compute-issue [some args] (first-not-nil [age-issue name-issue] some args))
; Where first-not-nil would be something like
(defn first-not-nil [fs & args]
(if (empty? fs)
nil
(let [result (apply (first fs) args)]
(if (nil? result)
(recur (rest fs) args)
result))))
I'm new to Clojure. Am I reinventing an existing function?
There is a similar function some-fn in clojure.core:
Takes a set of predicates and returns a function f that returns the first logical true value
returned by one of its composing predicates against any of its arguments, else it returns
logical false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical true result against the original predicates.
The key differences are some-fn returns another function for the actual function application, and that function will also discard false results, which it sounds like you may not want. This is another simple way to phrase it:
(defn first-not-nil [fs & args]
(first
(for [f fs
:let [r (apply f args)]
:when (some? r)]
r)))
I was writing an answer for this challenge, when I needed to give a recursive function an optional parameter. I ended up with something kind of equivalent to:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
My intent was for b? to act as an optional parameter. If it wasn't supplied, it would be defaulted to nil via destructuring.
Instead of running though, it gave me an error:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
After some debugging, I realized that for some reason the rest parameter wasn't a list as I'd expect, but just the passed number! The error was coming about because it tried to destructure the number.
I can fix it by getting rid of the wrapper list in the parameter list:
(defn func [a & b]
...
But this just looks wrong. I know the rest parameter should be a list, but b is actually just a number. If I use "unoptimized" recursion, it works as I'd expect:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Can anyone explain what's going on here?
This appears to be a known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
It's the last comment that describes the difference.
In a function definition:
(defn ^boolean =
;;other arities omitted...
([x y]
(if (nil? x)
(nil? y)
(or (identical? x y)
^boolean (-equiv x y))))
what does the ^boolean part in function definition mean? Does it only extend the metadata and signify the type of return, or does it have any deeper meaning? In other words, does it add any more value than simply making the code more self-described?
It is a type hint. See
https://www.safaribooksonline.com/library/view/clojure-programming/9781449310387/ch09s05.html
http://clojure-doc.org/articles/language/functions.html
or your favorite book. PLEASE NOTE: the compiler does not enforce that the actual type matches the type hint! Example w/o type hint:
(defn go []
"banana" )
(println (go))
;=> banana
(defn ^long go []
"banana" )
(println (go))
;=> Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number,
I am following along 'Clojure in Action' and I am confused by this :
(defn with-log [function-to-call log-statement ]
(fn [& args]
(println log-statement)
(apply function-to-call args)))
This is the segment of code that has me confused. This is what I can decipher so far:
(defn with-log [function-to-call log-statement ] ..) is defining a function with name "with-log" that takes arguments 'function-to-call' and 'log-statement' and function-to-call is a function being passed as a parameter to this function.
The next section is confusing to me : (fn [& args] .... is an anonymous function being defined here ? Is the 'with-log' function returning a new function definition ?
(fn [& args]
(println log-statement)
(apply function-to-call args))
So by calling (with-log somefunc "my label") -- is it just returing a new anonymous function ? Or is it invoking the anonymous function ?
with-log will yield a function that, when called, will do exactly what function-to-call did except with the side-effect that log-statement will be printed to *out* just before function-to-call is evaluated using the arguments given to the anonymous function.
This is an example of the Decorator Pattern - extending the behaviour of an existing function by wrapping it in another function i.e. the anonymous function created by with-log using the (fn ...) form.
In order for the decorator function with-log to work with any conceivable function-to-call, the anonymous function's argument list is specified so that it can be called with number of arguments using (fn [& args] ...). When the anonymous function calls function-to-call it 'unwraps' the argument list with the function apply).
Ways to make use of with-log might be:
((with-log some-fn "Calling some-fn") arg1 arg2)
or
(defn my-fn [a b]
(+ a b))
(def my-fn-with-logging (with-log my-fn "Calling my-fn"))
(my-fn 1 2) ; evaluates to 3
(my-fn-with-logging 1 2) ; prints "Calling my-fn" and evaluates to 3
It is returning the anonymous function, and it is not being called.
For example, this would invoke the anonymous function with the given arguments:
((with-log some-fn "log statement") arg1 arg2)
This works because the function being returned is the first item in the list, which means it gets invoked just like any other function would.
Yes, you're right. (fn ..) is a form which creates anonymous function. This piece of code, given a function f and some value s will return a function, which, when called, will print s and then invoke f:
user=> (defn with-log [function-to-call log-statement ]
(fn [& args]
(println log-statement)
(apply function-to-call args)))
#'user/with-log
user=> (with-log + "String")
#<user$with_log$fn__1 user$with_log$fn__1#147264b1>
user=> ((with-log + "String") 1 2 3)
String
6
user=>
Note the line starting with #<user$.... This is internal identifier of the anonymous function that just has been created, that is, simple call to with-log returns a function. And then we apply the same function (it is same in terms of its behavior; it will be different object in fact, because each call to with-log creates new "instance" of the same function) to a number of arguments. "String" string gets printed and then REPL shows us a result of (+ 1 2 3).
Here you can learn more about it.