Destructuring: How can this even work? - clojure

As an answer to a question on SO I was building a recurring function, and built my most complicated destructuring yet, which miraculously worked:
(defn fib?
[a b & [c & r]]
(if (= c (+ a b))
(if r
(recur b c r)
true)
false))
(fib? 0 1 1)
=> true
(fib? 2 3 5 8 13)
=> true
But I have no idea why it should work. The r used in therecur is a collection, something which would make the original function fail.
(fib? 2 3 [5 8 13])
=> false
I wanted to use something like apply recur there, but since recur is a special form, that's not possible. So I tried without it and it worked. Does recur have magical auto-apply properties or is there something else I'm not seeing.

The are two parts to the answer:
The "rest" parameter of a variadic function becomes the final parameter in any recur forms that recur to the top of the function. At this point it is no longer special in any way. You'll normally want to ensure that any values passed in that position actually are sequential, but even this is not enforced.1
Destructuring is just syntactic sugar provided by the fn and let macros. The desugared version of an fn form that uses destructuring in its parameter vector takes a certain number of regular arguments, then destructures them in a let form wrapping the entire body. Thus if you recur to the top of a function that uses destructuring in its parameter vector, the new values will be destructured for the next iteration.
1 For example, ((fn [& xs] (if (seq? xs) (recur (first xs)) xs)) 1 2 3) returns 1.

Related

clojure reduce. no start value, empty collection

In a riddle I have to complete the following expressions in order to evaluate to true. There must be one single insertion, which fits to all of them.
(= 15 (reduce __ [1 2 3 4 5]))
(= 0 (reduce __ []))
(= 6 (reduce __ 1 [2 3]))
The third expression provides a start value. Hence my replacement cannot provide another one.
This function would pass the first and the third truth test:
#(+ %1 %2)
However, the second expression yields the following error:
clojure.lang.ArityException: Wrong number of args (0) passed to (...my function id)
It looks like usually reduce calls the given function only if the length of start value + collection is bigger than 2. If this length is 0, like in the case above, it is called as well - with 0 arguments.
Does anyone have a hint how to carry on here?
From the comments, the solution is clearly +, but maybe it's valuable to look at it in some detail to see why. As it turns out, there's a lot to it.
First, let's look at reduce to see what the requirements are:
(defn reduce
"f should be a function of 2 arguments. If val is not supplied,
returns the result of applying f to the first 2 items in coll, then
applying f to that result and the 3rd item, etc. If coll contains no
items, f must accept no arguments as well, and reduce returns the
result of calling f with no arguments. ..."
...
([f coll]
(if (instance? clojure.lang.IReduce coll)
(.reduce ... coll f)
...))
([f val coll]
(if (instance? clojure.lang.IReduceInit coll)
(.reduce ... coll f val)
...)))
This is a multi-arity function that either takes a function and a collection, or a function, initial value and a collection.
+ is also a multi-arity function that behaves depending on how many arguments you pass to it. The source below (edited for the parts we care about), shows reduce is satisfied by 0-arity and 2-arity.
(defn +
"Returns the sum of nums. (+) returns 0..."
...
([] 0)
...
([x y] (. clojure.lang.Numbers (add x y)))
...
Clearly (reduce + []) calls the first clause and returns 0. Test 2 is explained.
This works for the first test by applying the add function to each pair of Numbers, which happens in the Java internals for Clojure, in a tight for loop.
The final test works exactly like the first, except it calls the [v val coll] implementation of reduce. This applies a slightly different internal function, but with the same effect.
Notes
[1]: IFn is the Java interface for clojure functions

Is it possible to do destructured head/tail separation of lazy sequences in clojure?

I see some examples that show we can get a nice head/tail destructuring of a sequence in clojure as follows:
(if-let [[x & xs] (seq coll)]
However I assume this won't work as desired for lazy sequences because this puts the values into a vector, which aren't lazy. I tried changing the vector form to a list form, and it gave me binding errors, quoted or not.
Without having binding like this, it seems that if I've got a lazy sequence where each element was a computationally-intensive equation of the previous element, I'd have to do that computation twice to get the head and tail as separate statements, right?
(let [head (first my-lazy-seq) ;; has to calculate the value of head.
tail (rest my-lazy-seq)] ;; also has to calculate the value of head to prepare the rest of the sequence.
Is there any way around this, or am I making an incorrect assumption somewhere?
user=> (let [[x & xs] (range)] [x (take 10 xs)])
[0 (1 2 3 4 5 6 7 8 9 10)]
xs is still a lazy seq, so you can use the destructuring with no problems. This will force the first element of xs, though. (Destructuring uses vector notation, but it doesn't necessarily use vectors under the covers.)
With respect to your second question: lazy seqs cache their results, so your second option would also work without extra recalculation. The head will only be calculated once.
The binding vector [x & xs] isn't actually constructing a vector at runtime. It's just the notation used for destructuring into head & tail.
So it works fine on infinite sequences:
(if-let [[x & xs] (range)]
(apply str x (take 9 xs)))
=> "0123456789"
The destructuring form is actually producing a lazy sequence in this case, which you can observe as follows:
(if-let [[x & xs :as my-seq] (range)]
(class my-seq))
=> clojure.lang.LazySeq

How do we do both left and right folds in Clojure?

Reduce works fine but it is more like fold-left.
Is there any other form of reduce that lets me fold to right ?
The reason that the clojure standard library only has fold-left (reduce) is actually very subtle and it is because clojure isn't lazy enough to get the main benefit of fold-right.
The main benefit of fold-right in languages like haskell is that it can actually short-circuit.
If we do foldr (&&) True [False, True, True, True, True] the way that it actually gets evaluated is very enlightening. The only thing it needs to evaluate is the function and with 1 argument (the first False). Once it gets there it knows the answer and does not need to evaluate ANY of the Trues.
If you look very closely at the picture:
you will see that although conceptually fold-right starts and the end of the list and moves towards the front, in actuality, it starts evaluating at the FRONT of the list.
This is an example of where lazy/curried functions and tail recursion can give benefits that clojure can't.
Bonus Section (for those interested)
Based on a recommendation from vemv, I would like to mention that Clojure added a new function to the core namespace to get around this limitation that Clojure can't have the lazy right fold. There is a function called reduced in the core namespace which allows you to make Clojure's reduce lazier. It can be used to short-circuit reduce by telling it not to look at the rest of the list. For instance, if you wanted to multiply lists of numbers but had reason to suspect that the list would occasionally contain zero and wanted to handle that as a special case by not looking at the remainder of the list once you encountered a zero, you could write the following multiply-all function (note the use of reduced to indicate that the final answer is 0 regardless of what the rest of the list is).
(defn multiply-all [coll]
(reduce
(fn [accumulator next-value]
(if (zero? next-value)
(reduced 0)
(* accumulator next-value)))
1
coll))
And then to prove that it short-circuits you could multiply an infinite list of numbers which happens to contain a zero and see that it does indeed terminate with the answer of 0
(multiply-all
(cycle [1 2 3 4 0]))
Let's look at a possible definition of each:
(defn foldl [f val coll]
(if (empty? coll) val
(foldl f (f val (first coll)) (rest coll))))
(defn foldr [f val coll]
(if (empty? coll) val
(f (foldr f val (rest coll)) (first coll))))
Notice that only foldl is in tail position, and the recursive call can be replaced by recur. So with recur, foldl will not take up stack space, while foldr will. That's why reduce is like foldl. Now let's try them out:
(foldl + 0 [1 2 3]) ;6
(foldl - 0 [1 2 3]) ;-6
(foldl conj [] [1 2 3]) ;[1 2 3]
(foldl conj '() [1 2 3]) ;(3 2 1)
(foldr + 0 [1 2 3]) ;6
(foldr - 0 [1 2 3]) ;-6
(foldr conj [] [1 2 3]) ;[3 2 1]
(foldr conj '() [1 2 3]) ;(1 2 3)
Is there some reason you want to fold right? I think the most common usage of foldr is to put together a list from front to back. In Clojure we don't need that because we can just use a vector instead. Another choice to avoid stack overflow is to use a lazy sequence:
(defn make-list [coll]
(lazy-seq
(cons (first coll) (rest coll))))
So, if you want to fold right, some efficient alternatives are
Use a vector instead.
Use a lazy sequence.
Use reduced to short-circuit reduce.
If you really want to dive down a rabbit hole, use a transducer.

Clojure: How does filter interact with logic?

I'm trying to learn Clojure, so I figured a good way to start would be to work through the project Euler challenges with it, and the first challenge is summing all of the number below 1000 that are divisible by 3 or 5.
My original code was:
(defn div3 [input-no] (zero? (mod input-no 3)))
(defn div5 [input-no] (zero? (mod input-no 5)))
(reduce + (filter (or div3 div5) (range 1 1000)))
But that didn't work, and it turned out that the filter would just return a list of numbers divisible by 3, and not those divisible by 5.
I changed my code to:
(defn div3or5 [input-no] (or (div3 input-no) (div5 input-no)))
(reduce + (filter div3or5 (range 1 1000)))
Which got the right result, but I don't know why my original code didn't work.
Could anyone shed some light on this?
The problem you are running into is that filter expects a predicate (a function taking an input and returning true or false) as its first argument. But while div3 and div5 are functions you can't simply combine them with or. You need to construct a new function that takes one argument and feeds this to both div3 and div5 and calls or and the results of both.
Fortunately this is easy to do in Clojure, try
(filter #(or (div3 %) (div5 %)) (range1 1000))
#() is shorthand for defining a function inline (also called a lambda) and you can get to the first argument with %1 to the second with %2 and so on. If there is only one argument then you can use % for %1 see this question.
You may also want to understand that #() is just syntactic sugar for the fn form which
looks like this: (fn [arg1 arg2 ... & restArgs] (forms)). #() has some limitations (for example it can't be nested).
If you just evaluate (or div3 div5) in the REPL you can see what is happening:
=> (or div3 div5)
#<user$div3 user$div3#73305c>
That is, or is evaluating to the function div3 (which filter is then using, giving the behaviour you describe).
The reason for this is or will return its first non-falsy argument (i.e. the first argument that isn't nil or false); in this case, the arguments are two function objects and a function object is not nil or false.
To put it another way, the or is happening on the functions themselves, not the results of the functions. As Paul said, you can use an anonymous function to make or act on the results rather than the functions themselves.

swap! alter and alike

I am having a problem understanding how these functions update the underlying ref, atom etc.
The docs say:
(apply f current-value-of-identity args)
(def one (atom 0))
(swap! one inc) ;; => 1
So I am wondering how it got "expanded" to the apply form. It's not mentioned what exactly 'args' in the apply form is. Is it a sequence of arguments or are these separate values?
Was it "expanded" to:
(apply inc 0) ; obviously this wouldnt work, so that leaves only one possibility
(apply inc 0 '())
(swap! one + 1 2 3) ;; #=> 7
Was it:
(apply + 1 1 2 3 '()) ;or
(apply + 1 [1 2 3])
(def two (atom []))
(swap! two conj 10 20) ;; #=> [10 20]
Was it:
(apply conj [] [10 20]) ;or
(apply conj [] 10 20 '())
The passage you quoted from swap!'s docstring means that what happens is the equivalent of swapping in a new value for the Atom obtained from the old one with (apply f old-value args), where args is a seq of all additional arguments passed to swap!.
What actually happens is different, but that's just an implementation detail. For the sake of curiosity: Atoms have a Java method called swap, which is overloaded to take from one to four arguments. The first one is always an IFn (the f passed to swap!); the second and third, in present, are the first two extra arguments to that IFn; the fourth, if present, is an ISeq of extra arguments beyond the first two. apply is never involved and the fixed arity cases don't even call the IFn's applyTo method (they just use invoke). This improves performance in the common case where not too many extra arguments are passed to swap!.