I have the following two test cases in Clojure, one destructuring a vector, and one destructuring a list:
user=> ((fn [[a op b]] (op a b)) [1 + 2])
3
user=> ((fn [[a op b]] (op a b)) '(1 + 2))
2
Why is the symbol + evaluated in the first test case but not the second? Is the quote recursive, so in the second test case op is really 'op?
You are correct that the single quote ' (equivalent of the function quote) will return a list of symbols, suppressing evaluation. However, since symbols cannot start with a number, the PersistentList '(1 + 2) will contain a java.lang.Long, a clojure.lang.Symbol, and a java.lang.Long.
When you invoke the function given by the Symbol + (which is possible because Symbol extends AFn which itself implements IFn, and overrides the invoke function), this gets executed:
public Object invoke(Object obj, Object notFound) {
return RT.get(obj, this, notFound);
}
Since you executed (op a b), or ('+ 1 2), obj is 1, notFound is 2, and this is the Symbol + in the call to clojure.lang.RT's get method, which looks like this:
static public Object get(Object coll, Object key, Object notFound){
if(coll instanceof ILookup)
return ((ILookup) coll).valAt(key, notFound);
return getFrom(coll, key, notFound);
}
Again, coll is the Long 1, key is the Symbol +, and notFound is the Long 2.
So when a function is called, it's being looked up in a collection. Since 1 is not a collection, the value notFound, or 2, is being returned.
As a visual of a ('+ 5 10) example, in a debugger:
First we can simply see if the forms are destructured the expected way or not with a simple println:
(def fn1
(fn [[a op b]]
(println "a>" a)
(println "b>" b)
(println "op>" op)
(op a b)))
(fn1 [1 + 2])
; a> 1
; b> 2
; op> #object[clojure.core$_PLUS_ 0x5b95b23d clojure.core$_PLUS_#5b95b23d]
(fn1 '(1 + 2))
; a> 1
; b> 2
; op> +
So in the first case, the parenthesis evaluates the clojure.core's function PLUS, which gives the expected (+ 1 2) => 3.
In the second case, you can picture the sequence of forms to be evaluated as an implicit sequence, so call eval on it will give:
(eval ('+ 1 2))
; 2
Which is simply the result of eval-ing each form in the sequence, and so only returns the last value, here 2.
You can think of it as:
(do
'+
1
2)
As hinted in the comment, do is not call.
The '+ is a clojure.lang.Symbol which implements IFn. Thus when calling eval, it will call the java function invoke, with two parameters 1 and 2.
(invoke 1 2) ; is called on +'
Looking at 2 parameters method of invoke for Symbol:
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Symbol.java#L129
We notice it will search for the symbol +' in the first parameter, which should be a map.
(def a {'+ 0})
(apply '+ [a 2])
; 0
When the item (here symbol) cannot be found, the invoke function returns the default value, the second parameter of the invoke function:
(def b { })
(apply '+ [b 2])
; symbol + is not found in b so returning 2
; 2
Related
I've put together a higher order function that in certain cases calls a function parameter, but it seems to have different effects depending on the function. I was able to reproduce the same behaviour just with a simple function:
(defn foo [f a b] (f a b))
For "normal" functions it works fine:
user=> (foo list 2 3)
(2 3)
user=> (foo cons 1 '(2 3))
(1 2 3)
user=> (foo println 2 3)
2 3
nil
But for operators, it does not, it just seems to return the last element:
user=> (foo '+ 2 3)
3
user=> (foo '* 2 3)
3
user=> (foo '- 2 3)
3
Why is this the case?
user=> (foo '+ 2 3)
3
Why is this the case?
' (or quote) is creating a symbol of + when you want the + function value itself: https://clojure.org/guides/weird_characters#_quote
(quote foo) => foo ;; symbol
'foo => foo ;; symbol
So the behavior of always returning the second argument comes from the fact that symbols (like keywords) also act as functions, typically used as a shorthand for get on associative structures (like maps), so these are functionally equivalent:
('foo 1 2) => 2
(get 1 'foo 2) => 2
The 2 happens to be in the position used for default values when the key isn't found in the associative structure.
This would be useful if you had a map with symbol keys, just like keywords:
('foo {'foo 1}) => 1
({'foo 1} 'foo) => 1
('foo {'bar 1} 2) => 2
In clojure, "operators" like + are just normal functions. Don't use the single-quote and it'll work fine.
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn foo [f a b] (f a b))
(dotest
(spyx (foo list 2 3))
(spyx (foo println 2 3))
(spyx (foo + 2 3))
(spyx (foo * 2 3))
(spyx (foo - 2 3)) )
with results:
(foo list 2 3) => (2 3)
2 3 ; result of (println 2 3)
(foo println 2 3) => nil ; println always returns `nil`
(foo + 2 3) => 5
(foo * 2 3) => 6
(foo - 2 3) => -1
The helper function spyx just prints an expression, then its value.
I'm trying to write a Clojure macro that creates a prefix notation list for evaluation from a simple infix notation list, say (2 * 3 + 4 * 2) to an evaluated(+ (* 2 3) (*4 2)) (resulting in 14 being returned).
I have written the following code:
(defmacro infix [op inlist]
(let [[i1 i2 & i3] inlist
last-group? (nil? (second i3))]
(if last-group?
`(if (= ~op ~i2)
(~i2 ~i1 ~(first i3)) ; return unevaluated prefix list
(~i1 ~i2 ~(first i3))) ; return unevaluated infix list
`(if (= ~op ~i2)
; recur with prefix list in i1 position
(infix ~op ~(conj (rest i3) (list i2 i1 (first i3)) ))
; return as list: i1 and i2, recur i3 (probably wrong)
(~i1 ~i2 (infix ~op ~i3))
))))
With the intention of enforcing operator precedence by calling the macro recursively with different op (operator function) parameters:
(infix + (infix * (2 * 3 + 4 * 2)))
Above, I'm just using it with two * and +, but ultimately I'd want to call the macro for all (or at least for the sake of this exercise, / * + -) operators.
When I execute the above nested macro call, I get the following error:
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'cbat.ch7.ex2/infix, compiling:(/tmp/form-init4661580047453041691.clj:1:1)
Calling the macro for a single operator and a list of the same operator (i.e. (infix * (2 * 3 * 4))) works as expected. If I call the macro with a single (i1 i2 i3) list, if op differs from i2, it tries to (understandably) return the unevaluated infix list with the error:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn cbat.ch7.ex2/eval3003 (form-init4661580047453041691.clj:1)
I was hoping calling the macro recursively would mean that I could process the unevaluated infix list before the entire line was evaluated, but this doesn't seem to work.
I'm pretty sure the else branch of the latter, inner if (i.e. (~i1 ~i2 (infix ~op ~i3))) is incorrect and I may just need the inner infix call, but I'm more concerned with getting the nested macro calls for the different operators working prior to evaluation.
I know that this isn't the usual way of converting infix to prefix notation, and have since found out about Dijkstra's shunting-yard algorithm, but please could someone kindly enlighten me as to:
whether such nested macro calls are possible?
whether my logic is reasonable, and not too far from a solution? If so...
... what changes I need to make to get things running?
I'm really focused on learning Clojure, so any thorough explanation (where possible) will be most welcome.
You can nest macro calls as this code demonstrates:
(defmacro mac [tag & forms]
`(do
(println "mac - enter" ~tag)
~#forms
(println "mac - exit " ~tag)))
(mac :a
(doseq [i (range 3)]
(mac :b (println i))))
mac - enter :a
mac - enter :b
0
mac - exit :b
mac - enter :b
1
mac - exit :b
mac - enter :b
2
mac - exit :b
mac - exit :a
You can also make recursive macro calls as this shows:
(defmacro macr [n]
(if (zero? n)
1
`(* ~n (macr ~(dec n)))))
(macr 5) => 120
Without delving too deep into your particular implementation, I would suggest 2 points:
At least to start, keep your forms as simple as possible. This means only forms like (2 + 3). And especially don't force the macro to figure out operator precedence in the early versions (or ever!).
Macros are almost never necessary, and it is unfortunate IMHO that they are somewhat "over-hyped" when learning Clojure & other lisps. I would suggest you don't even think about them for the first year or two, as they are more brittle than functions and less powerful in important ways (you can't pass a macro into a function, for example).
Update
Whenever you want to write something complicated (a macro definitely qualifies!), start small and
build it up one step at a time. Using the lein-test-refresh plugin and the Tupelo library definitely help
here.
First, make the simplest possible macro and observe its behavior:
(ns tst.clj.core
(:use clj.core clojure.test tupelo.test)
(:require [tupelo.core :as t] ))
(t/refer-tupelo)
(defn infix-fn [[a op b]]
(spyx a)
(spyx op)
(spyx b)
)
(defmacro infix [form]
(infix-fn form))
(infix (2 + 3))
a => 2
op => +
b => 3
For many macros, it is helpfully to send the marcro args to a helper function like infix-fn. The
spyx helps us by printing the symbol and its value. At this point, we can simply re-order the
args into prefix notation and away we go:
(defn infix-fn [[a op b]] (list op a b))
(defmacro infix [form] (infix-fn form))
(deftest master
(is= 5 (infix (2 + 3)))
(is= 6 (infix (2 * 3))))
What if we have a recursive tree structure? Check if we need to recurse in infix-fn:
(declare infix-fn)
(defn simplify [arg]
(if (list? arg)
(infix-fn arg)
arg))
(defn infix-fn [[a op b]]
(list op (simplify a) (simplify b)))
(is= 7 (infix ((2 * 2) + 3)))
(is= 9 (infix ((1 + 2) * 3)))
(is= 35 (infix ((2 + 3) * (3 + 4))))
(is= 26 (infix ((2 * 3) + (4 * 5))))
I would not want to add in the complication of operator precedence. If absolutely necessary, I
would not code it up myself but would use the excellent Instaparse library for that purpose.
expansion of your call would give you a clue:
(if (= + *)
(* infix (2 * 3 + 4 * 2))
(infix * (2 * 3 + 4 * 2)))
You've got the wrong presumption that the argument of macro would be expanded before the macro itself, i guess. But in fact in this one: (~i2 ~i1 ~(first i3)) i1 is still infix symbol. As far as i can see, the solution is to add some new condition branch, treating infix form some special way.
I solved the 58th 4clojure problem using recursion but then I looked at another persons solution and found this:
(fn [& fs] (reduce (fn [f g] #(f (apply g %&))) fs))
Which is more elegant than my solution. But I don't understand what %& means? (I do understand what % means but not when it's combined with &). Could anyone shed some light on this?
It means the "rest arguments", as per this source.
Arguments in the body are determined by the presence of argument
literals taking the form %, %n or %&. % is a synonym for %1, %n
designates the nth arg (1-based), and %& designates a rest arg.
Note that the & syntax is reminiscent of the & more arguments in function parameters (see here), but &% works inside an anonymous function shorthand.
Some code to compare anonymous functions and their anonymous function shorthand equivalent :
;; a fixed number of arguments (three in this case)
(#(println %1 %2 %3) 1 2 3)
((fn [a b c] (println a b c)) 1 2 3)
;; the result will be :
;;=>1 2 3
;;=>nil
;; a variable number of arguments (three or more in this case) :
((fn [a b c & more] (println a b c more)) 1 2 3 4 5)
(#(println %1 %2 %3 %&) 1 2 3 4 5)
;; the result will be :
;;=>1 2 3 (4 5)
;;=>nil
Note that the & more or %& syntax gives a list of the rest of the arguments.
What is the name of the construct in clojure that uses # at the begining of the expression a % in the middle? For example
#(fn [a b] (% b a))
I've tried searching the documentation for it but as both characters that define it aren't alphanumeric my search hasn't been too successful.
It is a reader macro for the anonymous function declaration. See http://clojure.org/reader for a comprehensive list of reader macros.
For instance, #(* 5 %) translates to (fn [x] (* 5 x)).
Your example translates in reading phase to (fn [op] (fn [a b] (op a b))) (op is my choice of placeholder there.)
It appears in (at least) two places:
Under Other Useful Functions and Macros (but that doesn't mention %1 %2 etc).
In the Reader (which parses the program) - # causes dispatch to a reader macro via a table lookup (you have to look carefully, but this does describe %1 etc)
In neither case does it have a useful name (actually, "Dispatch" could be the implied name - see second link). More generally "#" is called octothorp, amongst other things (here in Chile, "gato" (cat) for some unknown reason).
(And yes, %1 %2 are the first and second parameters, etc, while %& is "rest" - you can use just % for the first - see second link).
PS As everyone else has said, it's shorthand for a function. So (fn [a b] (+ a b)) is equivalent to #(+ %1 %2):
Clojure> (#(println % % %2) 1 2)
1 1 2
nil
Clojure> (#(apply println %&) 1 2 3)
1 2 3
nil
The #() construction is shorthand for the definition of an anonymous function. The % sign is used as shorthand for the arguments it takes.
% for the first argument. %integer for multiple arguments (ie %1 %2). %& for the rest (unused) arguments wrapped in a sequence.
=> (#(println % %2 %3 %&) 1 2 3 4 5)
1 2 3 (4 5)
You can see what function it creates by doing a macroexpand on it
#((\ %1 %2) * %2))
=> (macroexpand-1 '#((\ %1 %2) * %2))
(fn* [p1__744# p2__745#] ((\space p1__744# p2__745#) * p2__745#))
in normal words the following are the same:
#((\ %1 %2) * %2))
(fn [p1 p2] ((\ p1 p2) * p2))
Be careful to note that your example creates an anonymous function with a new anonymous function inside it.
"#" should be the lambda character, and % represents the first argument expected
I want to be able to do the following pseudocode:
Pass in symbol a.
Pass in symbol b.
Pass in an expression using a and b
As I change the value of a and b, print the output of c at each moment.
Ideally, I would like the signature to look like:
(runner a b (+ a b))
but I'm not sure that I'm approaching this correctly... I've tried changing the function to
(runner 'a 'b (+ 'a 'b))
and this more complicated example:
(runner 'a 'b (+ (* 'a 'b) 'a))
but this does a + on 'a and 'b before stepping into runner.
Here's my first stab at some clojure:
(defn runner [a b c] (
(for [i (range 10)
j (range 10)] (println i j (c i j))
What concept of clojure am I missing?
Function arguments are always evaluated before the function is called. If you want to defer evaluation or represent some computation or code as an object, you have a few options:
Use a function (see my code below)
Use a macro and splice some code into some other code that the macro generates
Pass code as a quoted list, and eval it.
Using a function is what you want to do 99% of the time. 1% of the time, you'll want macros. You should never need eval unless you're generating code at runtime or doing very screwy things.
user> (defn runner [f]
(doseq [a (range 3)
b (range 3)]
(println a b (f a b))))
#'user/runner
user> (runner (fn [x y] (+ x y)))
0 0 0
0 1 1
0 2 2
1 0 1
1 1 2
1 2 3
2 0 2
2 1 3
2 2 4
This could also be written as (runner #(+ %1 %2) or even simply (runner +).
There is no need to pass "a" and "b" into the function as arguments. doseq and for introduce their own local, lexically scoped names for things. There's no reason they should use a and b; any name will do. It's the same for fn. I used x and y here because it doesn't matter.
I could've used a and b in the fn body as well, but they would have been a different a and b than the ones the doseq sees. You may want to read up on scope if this doesn't make sense.
I would make its signature be something like
(runner alen blen op)
example:
(runner 10 10 +)
I'm not really sure i'm answering the correct question. I'm thinking "if i pass a function a symbol instead of a value how can it use the value that symbol represents? is that close?
(def a 4)
(defn my-inc [x] (+ (eval x) 1))
user> (my-inc 'a)
5
I'm sure there is a more elegant way than using eval.
It isn't clear enough to me what you're trying to achieve, but the following is an answer to what I guess is your question:
user=> (declare a b)
#'user/b
user=> (defn runner [] (+ a b))
#'user/runner
user=> (binding [a 1 b 2] (runner))
3
user=> (binding [a 2 b 3] (runner))
5
Note that the above style is likely not what you ought to be doing. Ask a better question and we'll give you better answers.