Nested partials in Clojure - clojure

How does the data structure get evaluated with the nested partials in the following:((partial (partial - 3)6)9). The inner partial yields -3, then we have ((partial -3)9).
But how why does partial then makes (-3 - 9)? Where does it get the subtraction instruction from?
I would like some helps about the manner of reading and evaluating of this data representation by Clojure.

The claim that ((partial - 3) 6) is called during the course of evaluating this expression is incorrect, and this is at the core of the misunderstanding.
To make this simpler, let's break down:
((partial (partial - 3) 6) 9)
...instead, rewriting it as:
(let [p1 (partial - 3)]
((partial p1 6) 9)
Now, what does (partial p1 6) return? A function which calls p1, with its first argument being 6, and any subsequent arguments appended. Thus, we could again write it more verbosely as:
(let [p1 (partial - 3)
p2 (partial p1 6)]
(p2 9)
Thus, (p2 9) calls (p1 6 9), which calls (- 3 6 9). (- 3 6) is never invoked anywhere in the execution process, so the initial function call of - is never consumed until the final invocation with all arguments present.
(The actual implementation may optimize the middle call away, folding p1's arguments into p2, but there's no need to incorporate such optimizations into the conceptual model; behavior is equivalent to the above).

Related

Using partial over a collection, reduce -vs- apply

I have this curious demonstration of partials. Here is the code:
Start by declaring a vector and a partial. As expected, reduce and apply sums the integers on vector a:
> (def a [1 2 3 4 5])
> (def p (partial + 10))
> (apply + a)
15
> (reduce + a)
15
Now, using apply on the partial p and vector a, I'm getting the sum of a and the +10 from the partial, which makes sense:
> (apply p a)
25
Now, using (reduce) makes no sense to me. Where is 55 coming from?
> (reduce p a)
55
The closest I can come up with is, (reduce) version is adding 10 from the 1 index and ignoring the zero index before adding everything together:
> (+ (first a) (reduce + (map #(+ % 10) (rest a))))
55
I'm just curious if anyone knows what is happening here, exactly? I don't really know what answer I'm expecting with this, but I also don't understand what is happening either. I have no idea why I would get 55 as an answer.
The first thing to note is that + is variadic: it can be called with zero, one, two, or more arguments. When you do (apply + a) you are essentially calling + with five arguments and getting the sum back (15).
However, reduce treats the function as strictly binary and calls it repeatedly, with the result of the previous call as the first argument of the next call. (reduce + a) is (+ (+ (+ (+ 1 2) 3) 4) 5) which also happens to be 15.
So your partial is also variadic and can be called with five arguments, as in the apply call: (apply p a) = (p 1 2 3 4 5) = (+ 10 1 2 3 4 5) so you get 25.
The reduce on p is going to call it repeatedly as shown above, but this time the function adds 10 in each time: (reduce p a) = (p (p (p (p 1 2) 3) 4) 5) = (+ 10 (+ 10 (+ 10 (+ 10 1 2) 3) 4) 5) so you get four 10s and the 15 making 55.
Another way of looking at Sean Corfield's fine answer:
Given
(def p (partial + 10))
then (p x y) means (+ 10 x y), for any x and y.
So
(reduce p a)
means
(reduce (fn [x y] (+ 10 x y)) a)
... since the first argument to reduce is a function of two arguments.
No initial value is supplied, so (first a) is used as such, and the reduction is applied to (rest a), which has four elements.
All the elements of a get added in: the first as the initial value;
the others by reduction.
The 10 gets added on in every cycle of the reduction: four times.
So the final result is the same as
(+ (* 10 (dec (count a))) (reduce + a))
In this case, 55.

Calling a macro on a macro

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.

Beginner Clojurist Lazy Sequence error: Don't know how to create ISeq from: java.lang.Long

I am new to Clojure and Lisp, but love it so far. I am currently trying to understand lazy-seq's and Clojure's ability to define infinite sequences. I have the following code:
(defn geometric
([] geometric 1)
([n] (cons n (lazy-seq (geometric (* n 1/2))))))
If I run:
(geometric)
in my REPL, it returns 1, as expected. However, if I run,
(take 10 (geometric))
I get the following error:
IllegalArgumentException Don't know how to create ISeq from:
java.lang.Long clojure.lang.RT.seqFrom
What I expect to get is:
(1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512)
Why am I getting this error? If I've understood correctly, one should be able to cons n to the lazy-sequence, and take should return the first ten values of the sequence, evaluated recursively.
One of my favorite functions: iterate takes a function f and a value x returning x, (f x), (f (f x), (f (f (f x))) etc.
Here is an elegant implementation with the same functionality:
(defn geometric []
(iterate #(/ % 2) 1))
Not a direct answer to your question but hopefully informative!
You have a small typo in your code:
(defn geometric
([] (geometric 1)) ;; notice the added parens around geometric 1
([n] (cons n (lazy-seq (geometric (* n 1/2))))))
Without this fix (geometric 1) was working because the implementation was to evaluate expression geometric (just a function value) which was discarded, then 1 expression was evaluated and returned as the function result (it was the last expression in this arity function body).
Now it works as expected:
(take 1 (geometric))
;; => (1)
(take 5 (geometric))
;; => (defn geometric
([] geometric 1)
([n] (cons n (lazy-seq (geometric (* n 1/2))))))
Notice that you cannot just call (geometric) safely in REPL as it will try to evaluate an infinite sequence.
Your problem is here:
([] geometric 1)
This expression means that, if geometric is called with no arguments, two things will happen:
The symbol geometric will be evaluated, which will result in the geometric function.
The number 1 will be returned.
What you probably meant was this:
([] (geometric 1))
This means that calling (geometric) is equivalent to calling (geometric 1). Your example will now work as expected:
(take 10 (geometric))
;=> (1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512)
(geometric) evaluates to the number 1, not to a sequence. (take 10 1) gives the same error that you're seeing now.
You should try running (take 10 (geometric 1)), since (geometric 1) will produce a sequence which can be supplied to the second argument of take.

Why + (or *) act different for than - (or /) with zero arguments?

When you call + with zero arguments
user=> (+)
0
I get 0 because it is invariant element to +. It works similar for *
user=> (*)
1
Why this does not work for - and / ?
user=> (-)
ArityException Wrong number of args (0) passed to: core/- clojure.lang.AFn.throwArity (AFn.java:429)
user=> (/)
ArityException Wrong number of args (0) passed to: core// clojure.lang.AFn.throwArity (AFn.java:429)
Note that - and / work differently when they are given a single argument: (- x 0) is different from (- x). The same for (/ x 1) and (/ x). The practical argument for + and * is that when your arguments may not be known beforehand, you can just apply or reduce over a list (possibly empty). The same is not true for division and negation, because you seldom need:
(apply / list)
You at least have one argument:
#(apply / (cons % list))
This is not authoritative, just a guess.
I guess the reason for this behaviour is the usage of + and * with aggregation functions: this allows to escape lots of boilerplate code in math formulas. Note the following:
(reduce + ()) => 0
(reduce * ()) => 1
the values are chosen not to affect the overall result of homogenous functions. Say you have to find the product of 10, 20, and all the items in some collection. That's what you do:
(defn product [items]
(* 10 20 (reduce * items)))
so when you have some items in a coll, it will work perfectly predictable:
(product [1 2 3]) => (* 10 20 (* 1 2 3))
and when the coll is empty you get the following:
(product []) => (* 10 20 1)
so it is exactly what you would expect.
Similar works for +
So why doesn't it work for - and / ?
i would say that they're not aggregation functions, traditionally they're opposite to aggregation. And in maths there are operators for + ( ∑ ) and * ( ∏ ), and no operators for - and /
Again, it's just a guess. Maybe there are some reasons that are much deeper.
the technical explanation would be:
if you check (source *),(source +) and (source -)
you will see that * and + can take 0 arguments while the - function will not.
(defn -
([x] (. clojure.lang.Numbers (minus x)))
([x y] (. clojure.lang.Numbers (minus x y)))
([x y & more]
(reduce1 - (- x y) more)))

Clojure: treat multiple arguments to < and +

Clojure allows for binary functions (every binary function?), in particular, +, to be applied to multiple args:
(+ 1 2 3) ; 6
I understand how it's treated (reduce-like on the list of arguments):
(+ (+ 1 2) 3) => (+ 3 3) => 6
Let's consider relations, say, <, = etc.:
(< 1 2 3) ; true
But now I don't understand how Clojure treats it. It can not be like in the sample above, because (< 1 2) is boolean value and comparison against integer is pointless:
(< 1 2 3) => (< (< 1 2) 3) => (< true 3) ; bad!
It's incorrect. In case of relations, there should be hidden and inside:
(< 1 2 3 4) => (and (< 1 2) (< 2 3) (< 3 4))
This is the questions. How are they treated? I mean, for me it's like there is no uniform treatment for functions (arg list essentially reduced with this function) and comparisons. Does Clojure make distinction between these cases?
Read the documentation
Returns non-nil if nums are in monotonically increasing order,
otherwise false.
Likewise for > nums must be in monotonically decreasing order.
If you read the source (linked from the docs), you see it's equivalent to your "hidden and"
([x y & more]
(if (< x y)
(if (next more)
(recur y (first more) (next more))
(< y (first more)))
false)))
Just read the docs:
"Returns non-nil if nums are in monotonically increasing order,
otherwise false."