I am defining a function "true-or-false" that will take an argument and print "1" if it is true and "0" if it is false but when I run my function with the argument:
(= 5 4)
it returns the error: "ClassCastException java.lang.Boolean cannot be cast to clojure.lang.IFn"
Code:
(defn true-or-false [x] (if (x)
(println "1")
(println "0")))
(def a (= 5 4))
(true-or-false a)
The clojure.lang.IFn interface provides access to invoking functions, but what you are passing to true-or-false appears to be a number. You shouldn't be wrapping x in parentheses inside if – that would mean you are invoking the x function call (see clojure.org reference on the if special form).
Related
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,
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.
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.
If I define a function that returns a function like this:
(defn add-n
[n]
(fn [x] (+ x n)))
I can then assign the result to a symbol:
(def add-1 (add-n 1))
and call it:
(add-1 41)
;=> 42
How do I call the result of (add-n 1) without assigning it to a new symbol? The following produces this output:
(println (add-n 1))
#<user$add_n$fn__33 user$add_n$fn__33#e9ac0f5>
nil
The #<user$add_n$fn__33 user$add_n$fn__33#e9ac0f5> is an internal reference to the generated function.
Easy:
(println ((add-n 1) 41))
The output you saw is a function definition. Putting it between round brackets and adding a parameter is enough to call it.
The following expression in clojure works great:
(doseq [x '(1 2 3 4)] (println x))
This one gives me a nullpointer:
(doseq [x '(1 2 3 4)] ((println x)(println "x")))
It produces the following output:
user=> (doseq [x '(1 2 3 4)] ((println x)(println "x")))
1
x
java.lang.NullPointerException (NO_SOURCE_FILE:0)
user=> (.printStackTrace *e)
java.lang.NullPointerException (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:4639)
at clojure.core$eval__5182.invoke(core.clj:1966)
at clojure.main$repl__7283$read_eval_print__7295.invoke(main.clj:180)
at clojure.main$repl__7283.doInvoke(main.clj:197)
at clojure.lang.RestFn.invoke(RestFn.java:426)
at clojure.main$repl_opt__7329.invoke(main.clj:251)
at clojure.main$legacy_repl__7354.invoke(main.clj:292)
at clojure.lang.Var.invoke(Var.java:359)
at clojure.main.legacy_repl(main.java:27)
at clojure.lang.Repl.main(Repl.java:20)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at jline.ConsoleRunner.main(ConsoleRunner.java:69)
Caused by: java.lang.NullPointerException
at user$eval__266.invoke(NO_SOURCE_FILE:26)
at clojure.lang.Compiler.eval(Compiler.java:4623)
... 14 more
nil
Just adding an extra set of parentheses around the body of a doseq gives me that nullpointer.
What am I doing wrong?
Well, you already figured out the solution, so just a few hints to explain the behavior:
In Clojure (just like in Lisp, Scheme, etc) everything is an expression and an expression is either an atom or a list. With regard to lists, the Clojure manual says
Non-empty Lists are considered calls
to either special forms, macros, or
functions. A call has the form
(operator operands*).
In your example, the body ((println x) (println x)) is a list and the operator is itself an expression which Clojure has to evaluate to obtain the actual operator. That is, you're saying "evaluate the first expression and take its return value as a function to invoke upon the second expression". However, println returns, as you noticed, only nil. This leads to the NullPointerException if nil is interpreted as an operator.
Your code works with (do (println x) (println x)) because do is a special form which evaluates each expression in turn and returns the value of the last expression. Here do is the operator and the expressions with println ar the operands.
To understand the usefulness of this behavior, note that functions are first-class objects in Clojure, e.g., you could return a function as a result from another function. For instance, take the following code:
(doseq [x '(1 2 3 4)] ((if (x > 2)
(fn [x] (println (+ x 2)))
(fn [x] (println (* x 3)))) x))
Here, I am dynamically figuring out the operator to invoke upon the element in the sequence. First, the if-expression is evaluated. If x is larger than two, the if evalutes to the function that prints x + 2, else it evaluates to the function that prints x * 3. This function is than applied to the x of the sequence.
I see you've already realised the problem, however please note you don't need a do:
(doseq [x '(1 2 3 4)] (println x) (println "x"))
doseq is (as the name suggests) a do already :)