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)))))
Related
This works:
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (tri* new-sum (+ n 1)))))))
but when I use recur in it, I get a CompilerException:
Mismatched argument count to recur, expected 0 args, got: 2
(defn tri*
([] (tri* 0 1))
([sum n]
(let [new-sum (+ sum n)]
(cons new-sum (lazy-seq (recur new-sum (+ n 1)))))))
lazy-seq is a macro which expands to code involving a zero-arg thunk that can be called later as the sequence is realized. You can see that the recur form is captured as the body of this thunk by doing
(macroexpand '(lazy-seq (recur new-sum (+ n 1))))
to get
(new clojure.lang.LazySeq (fn* [] (recur new-sum (+ n 1))))
which shows that the target of recur is the thunk, not tri*.
Another way to think about all of this is that the original call to tri* has long since completed (and returned a Cons object containing LazySeq rest object) by the time recur would be “evaluated.”
Your first version of tri* is fine in that the recursive call to tri* doesn't grow the stack, but instead simply creates a new set of Cons / LazySeq objects.
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
I am playing around and trying to create my own reductions implementation, so far I have this which works with this test data:
((fn [func & args]
(reduce (fn [acc item]
(conj acc (func (last acc) item))
)[(first args)] (first (rest args)))) * 2 [3 4 5]
What I don't like is how I am separating the args.
(first args) is what I would expect, i.e. 2 but (rest args) is ([3 4 5]) and so I am getting the remainder like this (first (rest args)) which I do not like.
Am I missing some trick that makes it easier to work with variadic arguments?
Variadic arguments are just about getting an unspecified number of arguments in a list, so all list/destructuring operations can be applied here.
For example:
(let [[fst & rst] a-list]
; fst is the first element
; rst is the rest
)
This is more readable than:
(let [fst (first a-list)
rst (rest a-list)]
; ...
)
You can go further to get the first and second elements of a list (assuming it has >1 elements) in one line:
(let [fst snd & rst]
; ...
)
I originally misread your question and thought you were trying to reimplement the reduce function. Here is a sample implementation I wrote for this answer which does’t use first or rest:
(defn myreduce
;; here we accept the form with no initial value
;; like in (myreduce * [2 3 4 5]), which is equivalent
;; to (myreduce * 2 [3 4 5]). Notice how we use destructuring
;; to get the first/rest of the list passed as a second
;; argument
([op [fst & rst]] (myreduce op fst rst))
;; we take an operator (function), accumulator and list of elements
([op acc els]
;; no elements? give the accumulator back
(if (empty? els)
acc
;; all the function's logic is in here
;; we're destructuring els to get its first (el) and rest (els)
(let [[el & els] els]
;; then apply again the function on the same operator,
;; using (op acc el) as the new accumulator, and the
;; rest of the previous elements list as the new
;; elements list
(recur op (op acc el) els)))))
I hope it helps you see how to work with list destructuring, which is probably what you want in your function. Here is a relevant blog post on this subject.
Tidying up your function.
As #bfontaine commented, you can use (second args) instead of (first (rest args)):
(defn reductions [func & args]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[(first args)]
(second args)))
This uses
func
(first args)
(second args)
... but ignores the rest of args.
So we can use destructuring to name the first and second elements of args - init and coll seem suitable - giving
(defn reductions [func & [init coll & _]]
(reduce
(fn [acc item] (conj acc (func (last acc) item)))
[init]
coll))
... where _ is the conventional name for the ignored argument, in this case a sequence.
We can get rid of it, simplifying to
(defn reductions [func & [init coll]] ... )
... and then to
(defn reductions [func init coll] ... )
... - a straightforward function of three arguments.
Dealing with the underlying problems.
Your function has two problems:
slowness
lack of laziness.
Slowness
The flashing red light in this function is the use of last in
(fn [acc item] (conj acc (func (last acc) item)))
This scans the whole of acc every time it is called, even if acc is a vector. So this reductions takes time proportional to the square of the length of coll: hopelessly slow for long sequences.
A simple fix is to replace (last acc) by (acc (dec (count acc))), which takes effectively constant time.
Lack of laziness
We still can't lazily use what the function produces. For example, it would be nice to encapsulate the sequence of factorials like this:
(def factorials (reductions * 1N (next (range)))))
With your reductions, this definition never returns.
You have to entirely recast your function to make it lazy. Let's modify the standard -lazy -reductions to employ destructuring:
(defn reductions [f init coll]
(cons
init
(lazy-seq
(when-let [[x & xs] (seq coll)]
(reductions f (f init x) xs)))))
Now we can define
(def factorials (reductions * 1N (next (range))))
Then, for example,
(take 10 factorials)
;(1N 1N 2N 6N 24N 120N 720N 5040N 40320N 362880N)
Another approach is to derive the sequence from itself, like a railway locomotive laying the track it travels on:
(defn reductions [f init coll]
(let [answer (lazy-seq (reductions f init coll))]
(cons init (map f answer coll))))
But this contains a hidden recursion (hidden from me, at least):
(nth (reductions * 1N (next (range))) 10000)
;StackOverflowError ...
I am having a problem running my program in Clojure. I just start learning Clojure a couple of weeks ago. So I don't know the quick and easy way to debug a Clojure program. My func2 raises an exception at (adj(a b)) as followed:
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn
user/func2.
I don't know what is wrong with it. Can someone point out the problem with my coding?
And in func3, I call func2 recursively, but it throws:
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lan g.AFn.throwArity (AFn.java:437)
What is wrong with func3? Thank you.
(defn adj [value1 value2]
(def result (+ (/ value1 2) (/ value2 2)))
(if (= (mod result 2) 1)
(+ result 1)
result
)
)
(defn func2 [list]
(let [[a b c d] list]
(inc d)
([(adj c a) (adj a b) (adj b c) d]))
)
(defn func3 [list]
(loop [v list r []]
(if(= (v 0) (v 1) (v 2))
(conj list r)
(func3(func2(list)))
))
)
What's the intended result of these functions? We probably need to see some sample inputs and expected results to really be able to help you.
Here's my attempt at cleaning them up. I've noted the changes I made as comments. func3 has the most serious problem in that it's an infinite recursion - there's no end condition. What should cause it to stop working and return a result?
(defn adj [value1 value2]
;; don't use def within functions, use let
(let [result (+ (/ value1 2) (/ value2 2))]
(if (= (mod result 2) 1)
(+ result 1)
result)))
(defn func2 [list]
(let [[a b c d] list]
;; The extra parens around this vector were causing it
;; to be called as a function, which I don't think is
;; what you intended:
[(adj c a) (adj a b) (adj b c) d]))
;; This needs an end condition - it's an infinite recursion
(defn func3 [list]
(loop [v list r []]
(if (= (v 0) (v 1) (v 2))
(conj list r)
;; Removed extra parens around list
(func3 (func2 list)))))
The reason I say not to use def within functions is that it always creates a global function. For local bindings you want let.
Regarding the extra parens, the difference between [1 2 3] and ([1 2 3]) is that the former returns a vector containing the numbers 1, 2, and 3, whereas the latter tries to call that vector as a function. You had excess parens around the literal vector in func2 and around list in func3, which was causing exceptions.
As a style note, the name list isn't a good choice. For one thing, it's shadowing clojure.core/list, and for another you're probably using vectors rather than lists anyway. It would be more idiomatic to use coll (for collection) or s (for sequence) as the name.
This would suggest at least one other change. In func3 you use a vector-only feature (using the vector as a function to perform lookup by index), so to be more general (accept other data structures) you can convert to a vector with vec:
(defn func3 [coll]
(loop [v (vec coll) r []]
(if (= (v 0) (v 1) (v 2))
(conj v r)
(func3 (func2 v)))))
Oh, there is no need to debug that. I suggest you have a look at LightTable.
The first two functions are easily fixed:
(defn adj [value1 value2]
;(def result (+ (/ value1 2) (/ value2 2))) def creates a global binding in current namespace !!!
(let [result (+ (/ value1 2) (/ value2 2))]
(if
(= (mod result 2) 1)
(inc result)
result)))
(defn func2 [xx]
(let [[a b c d] xx]
[ (adj c a) (adj a b) (adj b c) (inc d)]
))
The third function is not clear to me. I don't read your intent. What I understand is: "Keep applying func2 to itself until the first three elements of its result are equal." But I'm afraid this condition is never met, so I replaced it with a true in order to see just one result without blowing the stack.
(defn func3 [xx]
(loop [ v (func2 xx) ]
(if
;(= (v 0) (v 1) (v 2))
true
v
(recur (func2 v))
)))
Useful link: http://clojure.org/cheatsheet
Cheers -
I am trying to achieve one of the functions in my program. I have list=[a b c] as a parameter in func3. I want to test an equality of these items. If they are not equal I will call it again using another list return from func2.
Here is what I need to do. I want the Conj to do this [list list1 list2 list3] until func3 have the items that are equal. In my function, I want conj to merge an empty vector r[] to other lists when the condition is false.All I get right now is a final list return when the condition is true. Assume that the condition must be false(items are not equal) before getting true. Can someone help me to use the conj in the false condition.Thank you.
;input [1 2 3]
;output [[1 2 3][1 3 4] [3 4 5] ]// numbers for demo only
(defn func3 [list]
(loop [v (vec list) r []]
(if(= (v 0) (v 1) (v 2))
(conj r v)
(let[result (func2 v)]
;i want to merge result to r until the condition is true
(conj r result)
(func3 result)))))
Conj never changes its input, it creates a new output based on the input. In the second condition, you are not doing anything to the output of conj, so its result is never used.
(defn func3 [list]
(loop [[v & vs] (vec list) r []]
(if (= (v 0) (v 1) (v 2))
(conj r v)
(let [result (func2 v)
r (conj r result)]
(recur vs r)))))
I understand that you have a list of three elements as an initial input, want to compare them for equality. In case they match, you want to append the list to a later returned accumulator - in case they don't, you want to transform the list using a function idiomatically called func2 and try that procedure again.
EDIT: Since you have commented how your function should work, here comes an implementation:
(defn func3
"Determines whether items in coll are equal. If not, transforms coll with func2 and
repeats the test until a coll with equal elements could be found.
Returns a vector of all tried versions."
[coll]
(loop [acc []
coll coll]
(if (apply = coll)
(conj acc coll)
(recur (conj acc coll)
(func2 coll)))))
Here is a lazy implementation:
(defn func3
[coll]
(-> (->> coll
(iterate func2)
(split-with (partial apply =)))
(as-> [dropped [r]]
(concat dropped [r])))