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.
Related
I am trying to write a container function that takes a function name, it's arguments, and calls the function with an additional argument.
I am pretty sure I am doing this wrong, but here's what I've got so far.
(defn get-dyn [& args]
((first args) "some" (rest args)))
So, the first argument is the function name, and that function can have any number of arguments so I guess I have to accept optional parameter?
I need to inject a common argument "some" into all the functions I call via this function.
so,
(get-dyn str 3 4)
(get-dyn str 32 "willhelm")
etc.. and I would expect it to be equivalent of doing
(str "some" 3 4)
(str "some" 32 "wilhelm")
Except, the (rest args) returns a set so it doesn't work that way.
I tried doing it with partial but couldn't work it out.
Is there a way I can solve this problem? or am I better of using induvidual functions?
You can use apply.
user> (defn get-dyn [f & args]
(apply f "some" args))
#'user/get-dyn
user> (get-dyn str 1 2)
"some12"
user> (get-dyn str " " 1 " " 2)
"some 1 2"
I'm trying to understand how this function work, which is an implementation of comp (from the chapter "Functional Programming" in the book Clojure for the Brave and True):
(defn two-comp
[f g]
(fn [& args]
(f (apply g args))))
The idea is that it takes two functions and apply them to args. What I don't understand is how the args reach the anonymous function, since they are not entered as arguments to two-comp? How can be two-comp used this way?
two-comp returns an anonymous function, which in turn takes args. Look at the body of two-comp:
(fn [& args]
(f (apply g args)))
fn creates a function, and that function definition follows. The return value of fn is what is returned from two-comp.
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 doing the closure tutorial at http://clojurescriptkoans.com and I am stuck here: http://clojurescriptkoans.com/#functions/9
It looks like this
Higher-order functions take function arguments
(= 25 ( _ (fn [n] (* n n))))
I am supposed to fill in something at the underscore to make the expression true. I have no clue what to do.
The syntax simply consists of binding the function, and then calling it.
Since this is an exercise, I will show a similar situation rather than showing the exercise's solution:
user> ((fn [f] (f "abc")) (fn [s] (str s s s)))
"abcabcabc"
here I bind the argument of the first function to f, and call f with the argument "abc".
or you can use the short-hand notation:
#(%1 5)
Higher order functions takes functions as arguments.
Defining two functions
user=> (defn multiply [n] (* n n))
#'user/multiply
user=> (defn add [n] (+ n n))
#'user/add
Defining higher order function
user=> (defn highorderfn [fn number] (fn number))
#'user/highorderfn
Calling the higher order function
user=> (highorderfn multiply 5)
25
user=> (highorderfn add 5)
10
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.