How do I pattern match on array size in clojure? - clojure

I want to write a function to return the sum of all numbers divisible by 3 in a given list. I don't know how to pattern match on the size of a list. I get a nil pointer exception when I run the following code.
I am trying to do this using first principles, instead of using loop map and reduce
(defn sum3
[[head & tail]]
(if (= (mod head 3) 0)
(+ head (sum3 tail))
(sum3 tail))
[[head]]
(if (= (mod head 3) 0)
head
0))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println (sum3 [1 2 3])))

Function dispatch in clojure is done on the number of arguments to the function and not on the number of destructured values in the function call.
Once the appropriate arity has been selected, and the function has started running, the destructuring occurs and binds the symbols to the desctructured values.
Fortunatly clojure offers arbitrary custom function dispatch in the form of multimethods so if you want to dispatch based on the length of the arguments you can. For your example it's overkill though not particularly hard. There are other cases where it makes sense.
A normal, single arity, approach to this function would look like this:
user> (defn sum3
[[head & tail]]
(if (seq tail)
(if (= (mod head 3) 0)
(+ head (sum3 tail))
(sum3 tail))
(if (= (mod head 3) 0)
head
0)))
#'user/sum3
user> (sum3 [1 2 3 4 5 6])
9
You should in general always use recur rather than direct recursion though for this question it's not too much of an issue when demonstrating this principal .

First let's do the version using reduce:
(defn sum3 [coll]
(reduce (fn [sum el]
(if (zero? (mod el 3))
(+ sum el)
sum)) 0 coll))
Notice the use of zero?. No need for pattern-matching here.
Then we can go on to use recursivity:
(defn sum3
([coll] (sum3 0 coll))
([sum [head & tail]]
(let [add (if (zero? (mod head 3))
(+ sum head)
sum)]
(if tail
(recur add tail)
add))))
Again, no pattern matching (you would have to use core.match for that -clojure does not use pattern matching). The dispatch is only made using the number of arguments. This is why your function was not valid syntax: it was in both cases a 1-arity function. Note the use of recur to recurse the function. It can only be used for tail-recursion.
We could make it a 1-arity function without dispatching on arguments as well:
(defn sum3
[[head & tail]]
(let [m3? (zero? (mod head 3))]
(if (seq tail)
(if m3?
(+ head (sum3 tail))
(sum3 tail))
(if m3? head 0))))
Note that this version is not tail-recursive and will overflow for big inputs.
But really the reduce version - or even the loop version look much better.

in fact the main error is in the defn syntax. You don't define two arities here, rather make one arity [[head]] and then goes the body, which is totally valid clojure code. To make 2 arities you should put each into brackets:
(defn sum3
([[head]]
(if (= (mod head 3) 0)
head
0))
([[head & tail]]
(if (= (mod head 3) 0)
(+ head (sum3 tail))
(sum3 tail))))
but it would also fail
because you don't define different arities, they are equal (one argument call), so the compiler would produce an error. Clojure destructuring is not pattern matching at all. It is just a way of retrieving items from a collection. But you can fix this (emulate kind of length pattern matching) with a minor change:
user>
(defn sum3
([head]
(if (= (mod head 3) 0)
head
0))
([head & tail]
(if (= (mod head 3) 0)
(+ head (apply sum3 tail))
(apply sum3 tail))))
#'user/sum3
user> (sum3 1 2 3 4 5 6)
9
user> (apply sum3 [1 2 3 4 5 6])
9
now you have fair variant with two different arities.
But yes, it is not tail recursive, so in real life you would go with reduce or loop/recur

Related

How to make reduce more readable in Clojure?

A reduce call has its f argument first. Visually speaking, this is often the biggest part of the form.
e.g.
(reduce
(fn [[longest current] x]
(let [tail (last current)
next-seq (if (or (not tail) (> x tail))
(conj current x)
[x])
new-longest (if (> (count next-seq) (count longest))
next-seq
longest)]
[new-longest next-seq]))
[[][]]
col))
The problem is, the val argument (in this case [[][]]) and col argument come afterward, below, and it's a long way for your eyes to travel to match those with the parameters of f.
It would look more readable to me if it were in this order instead:
(reduceb val col
(fn [x y]
...))
Should I implement this macro, or am I approaching this entirely wrong in the first place?
You certainly shouldn't write that macro, since it is easily written as a function instead. I'm not super keen on writing it as a function, either, though; if you really want to pair the reduce with its last two args, you could write:
(-> (fn [x y]
...)
(reduce init coll))
Personally when I need a large function like this, I find that a comma actually serves as a good visual anchor, and makes it easier to tell that two forms are on that last line:
(reduce (fn [x y]
...)
init, coll)
Better still is usually to not write such a large reduce in the first place. Here you're combining at least two steps into one rather large and difficult step, by trying to find all at once the longest decreasing subsequence. Instead, try splitting the collection up into decreasing subsequences, and then take the largest one.
(defn decreasing-subsequences [xs]
(lazy-seq
(cond (empty? xs) []
(not (next xs)) (list xs)
:else (let [[x & [y :as more]] xs
remainder (decreasing-subsequences more)]
(if (> y x)
(cons [x] remainder)
(cons (cons x (first remainder)) (rest remainder)))))))
Then you can replace your reduce with:
(apply max-key count (decreasing-subsequences xs))
Now, the lazy function is not particularly shorter than your reduce, but it is doing one single thing, which means it can be understood more easily; also, it has a name (giving you a hint as to what it's supposed to do), and it can be reused in contexts where you're looking for some other property based on decreasing subsequences, not just the longest. You can even reuse it more often than that, if you replace the > in (> y x) with a function parameter, allowing you to split up into subsequences based on any predicate. Plus, as mentioned it is lazy, so you can use it in situations where a reduce of any sort would be impossible.
Speaking of ease of understanding, as you can see I misunderstood what your function is supposed to do when reading it. I'll leave as an exercise for you the task of converting this to strictly-increasing subsequences, where it looked to me like you were computing decreasing subsequences.
You don't have to use reduce or recursion to get the descending (or ascending) sequences. Here we are returning all the descending sequences in order from longest to shortest:
(def in [3 2 1 0 -1 2 7 6 7 6 5 4 3 2])
(defn descending-sequences [xs]
(->> xs
(partition 2 1)
(map (juxt (fn [[x y]] (> x y)) identity))
(partition-by first)
(filter ffirst)
(map #(let [xs' (mapcat second %)]
(take-nth 2 (cons (first xs') xs'))))
(sort-by (comp - count))))
(descending-sequences in)
;;=> ((7 6 5 4 3 2) (3 2 1 0 -1) (7 6))
(partition 2 1) gives every possible comparison and partition-by allows you to mark out the runs of continuous decreases. At this point you can already see the answer and the rest of the code is removing the baggage that is no longer needed.
If you want the ascending sequences instead then you only need to change the < to a >:
;;=> ((-1 2 7) (6 7))
If, as in the question, you only want the longest sequence then put a first as the last function call in the thread last macro. Alternatively replace the sort-by with:
(apply max-key count)
For maximum readability you can name the operations:
(defn greatest-continuous [op xs]
(let [op-pair? (fn [[x y]] (op x y))
take-every-second #(take-nth 2 (cons (first %) %))
make-canonical #(take-every-second (apply concat %))]
(->> xs
(partition 2 1)
(partition-by op-pair?)
(filter (comp op-pair? first))
(map make-canonical)
(apply max-key count))))
I feel your pain...they can be hard to read.
I see 2 possible improvements. The simplest is to write a wrapper similar to the Plumatic Plumbing defnk style:
(fnk-reduce { :fn (fn [state val] ... <new state value>)
:init []
:coll some-collection } )
so the function call has a single map arg, where each of the 3 pieces is labelled & can come in any order in the map literal.
Another possibility is to just extract the reducing fn and give it a name. This can be either internal or external to the code expression containing the reduce:
(let [glommer (fn [state value] (into state value)) ]
(reduce glommer #{} some-coll))
or possibly
(defn glommer [state value] (into state value))
(reduce glommer #{} some-coll))
As always, anything that increases clarity is preferred. If you haven't noticed already, I'm a big fan of Martin Fowler's idea of Introduce Explaining Variable refactoring. :)
I will apologize in advance for posting a longer solution to something where you wanted more brevity/clarity.
We are in the new age of clojure transducers and it appears a bit that your solution was passing the "longest" and "current" forward for record-keeping. Rather than passing that state forward, a stateful transducer would do the trick.
(def longest-decreasing
(fn [rf]
(let [longest (volatile! [])
current (volatile! [])
tail (volatile! nil)]
(fn
([] (rf))
([result] (transduce identity rf result))
([result x] (do (if (or (nil? #tail) (< x #tail))
(if (> (count (vswap! current conj (vreset! tail x)))
(count #longest))
(vreset! longest #current))
(vreset! current [(vreset! tail x)]))
#longest)))))))
Before you dismiss this approach, realize that it just gives you the right answer and you can do some different things with it:
(def coll [2 1 10 9 8 40])
(transduce longest-decreasing conj coll) ;; => [10 9 8]
(transduce longest-decreasing + coll) ;; => 27
(reductions (longest-decreasing conj) [] coll) ;; => ([] [2] [2 1] [2 1] [2 1] [10 9 8] [10 9 8])
Again, I know that this may appear longer but the potential to compose this with other transducers might be worth the effort (not sure if my airity 1 breaks that??)
I believe that iterate can be a more readable substitute for reduce. For example here is the iteratee function that iterate will use to solve this problem:
(defn step-state-hof [op]
(fn [{:keys [unprocessed current answer]}]
(let [[x y & more] unprocessed]
(let [next-current (if (op x y)
(conj current y)
[y])
next-answer (if (> (count next-current) (count answer))
next-current
answer)]
{:unprocessed (cons y more)
:current next-current
:answer next-answer}))))
current is built up until it becomes longer than answer, in which case a new answer is created. Whenever the condition op is not satisfied we start again building up a new current.
iterate itself returns an infinite sequence, so needs to be stopped when the iteratee has been called the right number of times:
(def in [3 2 1 0 -1 2 7 6 7 6 5 4 3 2])
(->> (iterate (step-state-hof >) {:unprocessed (rest in)
:current (vec (take 1 in))})
(drop (- (count in) 2))
first
:answer)
;;=> [7 6 5 4 3 2]
Often you would use a drop-while or take-while to short circuit just when the answer has been obtained. We could so that here however there is no short circuiting required as we know in advance that the inner function of step-state-hof needs to be called (- (count in) 1) times. That is one less than the count because it is processing two elements at a time. Note that first is forcing the final call.
I wanted this order for the form:
reduce
val, col
f
I was able to figure out that this technically satisfies my requirements:
> (apply reduce
(->>
[0 [1 2 3 4]]
(cons
(fn [acc x]
(+ acc x)))))
10
But it's not the easiest thing to read.
This looks much simpler:
> (defn reduce< [val col f]
(reduce f val col))
nil
> (reduce< 0 [1 2 3 4]
(fn [acc x]
(+ acc x)))
10
(< is shorthand for "parameters are rotated left"). Using reduce<, I can see what's being passed to f by the time my eyes get to the f argument, so I can just focus on reading the f implementation (which may get pretty long). Additionally, if f does get long, I no longer have to visually check the indentation of the val and col arguments to determine that they belong to the reduce symbol way farther up. I personally think this is more readable than binding f to a symbol before calling reduce, especially since fn can still accept a name for clarity.
This is a general solution, but the other answers here provide many good alternative ways to solve the specific problem I gave as an example.

What is wrong with my Clojure implementation of permutations

I know that there are multiple ways to solve permutations using Clojure.
I have tried creating a DCG (definite clause grammar) using Core.Logic but
the DCG part of the library is too experimental and didn't work.
In the code below I try two different approaches. One is a list comprehension (commented out), which is similar to the way I would solve this problem in Haskell.
The second approach uses MapCat to apply cons/first to each return value from the
recursive call to permutation. Remove item makes sure that I don't use the same letter more than once for each position.
Can someone please explain what is wrong with the list comprehension approach and what is wrong with the MapCat approach. It is much easier to reason about this kind of problem in Haskell - is there some perspective I am missing about Clojure?
(defn remove-item [xs]
(remove #{(first xs)} xs )
)
(defn permutation [xs]
(if (= (count xs) 1)
xs
;(for [x xs y (permutation (remove-item xs))
; :let [z (map concat y)]]
; z)
(mapcat #(map cons first (permutation (remove-item %)) ) xs)
)
)
Edit: #thumbnail solved the MapCat sub-problem in the comments already
We can simplify the permutation function to
(defn permutation [xs]
(if (= (count xs) 1)
xs
(for [x xs
y (permutation (remove-item xs))]
(map concat y))))
Attempting to use it on anything plural produces java.lang.IllegalArgumentException: Don't know how to create ISeq from: ... whatever you are trying to permute.
There are two errors:
permutation should return a sequence of sequences, even when there is
only one of them; so xs should be (list xs). This is what causes the exception.
The permutation for a given x from xs and, given that, a permutation y of xs without xis just (cons x y).
With these corrected, we have
(defn permutation [xs]
(if (= (count xs) 1)
(list xs)
(for [x xs
y (permutation (remove-item x xs))]
(cons x y))))
For example,
(permutation (range 3))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
The above works only if all the permuted things are different. At the other extreme ...
(permutation [1 1 1])
;()
Also,
count scans the whole of a sequence. To find out if there is only
one element, (seq (rest xs)) is faster than (= (count xs) 1).
And the remove in remove-item scans the whole sequence. There is
little we can do to mend this.
If we know that we are dealing with distinct things, it is simpler and faster to deal with them as a set:
(defn perm-set [xs]
(case (count xs)
0 '()
1 (list (seq xs))
(for [x xs, y (perm-set (disj xs x))]
(cons x y)))
It works for empty sets too.
count is instant and disj is almost constant time, so this is
faster.
Thus:
(perm-set (set '()))
;()
(perm-set (set (range 3)))
;((0 1 2) (0 2 1) (1 0 2) (1 2 0) (2 0 1) (2 1 0))
We can add support for duplicates by working with the index of the items in the original sequence. The function append-index returns a new sequence where the index and value are now in a vector. For example '(\a \b \c) -> '([0 \a] [1 \b] [2 \c] [3 \a]).
You then work with this sequence within the for loop, taking the index of the item when we want to remove it from the original and taking the value when we cons it to the tail sequence.
(defn remove-nth [coll n]
(into (drop (inc n) coll) (reverse (take n coll))))
(defn append-index [coll]
(map-indexed #(conj [%1] %2) coll))
(defn permutation [xs]
(let [i-xs (append-index xs)]
(if (= (count xs) 1)
(list xs)
(for [x i-xs
y (permutation (remove-nth xs (first x)))]
(cons (last x) y)))))
Thanks to the previous post, I was struggling with the permutation problem myself and had not considered using a for comprehension.

Fibonacci numbers in Clojure

I'm learning Clojure. Quite basic task is to generate Fibonacci sequence. I end up with pretty much copy of the imperative solution (and list is reversed, huh):
(defn n-fib [n]
(if (= n 1) '(1)
(loop [i 2 l '(1 1)]
(if (= i n)
l
(recur (inc i) (cons (+ (fst l) (snd l)) l))))))
What is the better way, more functional, concise? Lazy sequences? How to use them? For example, in Haskell using laziness I can write one liner:
fib = 1 : 1 : zipWith + (tail fib)
Note that Haskell solution offers infinite sequence (laziness...). If Clojure both eager and lazy solutions can be (even like get n-length list) I would like to know both.
Update: Another solution I got yields not reversed list, but it uses stack to generate it:
(defn n-fib [n]
(defn gen [i a b]
(if (= i 0)
()
(cons (+ a b) (gen (dec i) b (+ a b)))))
(gen n 0 1))
You might want to look at http://en.wikibooks.org/wiki/Clojure_Programming/Examples/Lazy_Fibonacci
The equivalent to your lazy Haskell solution is this
(def fib (lazy-cat [1 1] (map + (rest fib) fib)))
This one doesn't generate the whole sequence, but it is good at finding the nth fibonacci number with an iterative algorithm. I'm only just learning clojure, so I'd be interested what people think about this approach and if there's something wrong with it. It's not pretty, and it's not clever, but it does seem to work.
(defn fib [n]
(if (< n 2)
n
(loop [i 1
lst 0
nxt 1]
(if (>= i n)
nxt
(recur (inc i) nxt (+' lst nxt))))))

Clojure tail call recursion with variable argument function

I basically want this:
(defn mymax
([a b] (if (> a b) a b))
([a b & rest] (apply recur (conj rest (mymax a b)))))
So that: (mymax 1 2 3 4) tail calls (mymax 2 3 4) which tail calls (mymax 3 4)
I see the problem that "apply" stops recur being in the tail position, which means it won't work. But I don't see how I can not use apply for variable arguement functions
[Note, I know you can solve this particular problem with reduce. Just wondering if you can do tail-call-recursion with variable params]
Make the function take a single vector as an argument rather than using aruguments as the sequence of values. That would allow you to get rid of apply.
(defn mymax [[a b & rest]]
(let [m (if (> a b) a b)]
(if (not rest)
m
(recur (conj rest m)))))

Weird behaviour binding in loop recursion

I'm learning Clojure, and I'm trying to solve the Problem 31: Write a function which packs consecutive duplicates into sub-lists.
(= (__ [1 1 2 1 1 1 3 3]) '((1 1) (2) (1 1 1) (3 3)))
I know I can solve this using identity, and in a functional way, but I want to solve it using recursion, because I've not well established this idea in my brain.
My solution would be this:
(defn packing [lista]
(loop [[fst snd :as all] lista mem [] tmp '(fst)]
(print "all is " all "\n\n") ;; something is wrong; it always is an empty list
(if (seq? all)
(if (= fst snd)
(recur (rest all) mem (cons snd tmp))
(recur (rest all) (conj mem tmp) (list snd)))
(seq mem))))
My idea is a recursive loop always taking the first 2 items and comparing. If they are the same number, I include this inside a temporary list tmp; if they're different, I include my temporary list inside men. (This is my final list; a better name would be final_list.)
Because it compares the first 2 items, but at the same time it needs a recursive loop only bypassing the first item, I named the entire list all.
I don't know if the logic is good but inclusive if this was wrong I'm not sure why when I print.
(print "all is " all "\n\n") I receive an empty list
A few points:
'(fst) creates a list containing a symbol fst, not the value of fst, this is one of the reasons to prefer using vectors, e.g., [fst]
you should avoid assuming the input will not be empty
you can use conj for both lists and vectors
destructuring is nestable
(defn packing [coll]
(loop [[x & [y :as more] :as all] coll
result []
same '()]
(if all
(if (= x y)
(recur more result (conj same x))
(recur more (conj result (conj same x)) '()))
result)))
in your code all isn't empty..only happen than is an infinite loop and you always see a empty list...in the firsts lines you can see than it works like expected..
the mistake is in (seq? all) because a empty list is a seq too... try (seq? '()) and return true...then you do a empty loop
you need change this for (empty? all) your code would be
other mistake is '(fst) because it return the simbol fst and not the value...change it for (list fst)
(defn badpacking [lista]
(loop [[fst snd :as all] lista mem [] tmp (list fst)]
(if (empty? all)
(seq mem)
(if (= fst snd)
(recur (rest all) mem (cons snd tmp))
(recur (rest all) (conj mem tmp) (list snd))))))