Defining my own max function with variable arguments - clojure

I'm learning Clojure solving the problems listed on 4clojure. One of the exercises is to create your own max function with variable arguments.
I'm trying to solve this easy problem using the REPL and I got to this solution:
(defn my-max
[first & more] (calc-max first more))
(defn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
Which works fine but the exercise doesn't allow the use of def and therefore I must crunch both functions into one. When I replace the calc-max reference with its code the result is:
(defn my-max
[first & more]
((fn calc-max
[m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else calc-max m (rest x)))
first more))
But this code doesn't work and returns the next error:
user=> (my-max 12 3 4 5 612 3)
java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
I guess this error comes from trying to evaluate the result of the calc-max function and I guess it's a syntax error on my part, but I can't figure out how to resolve it.

Here is the function I used to solve it. The point is not to use max at all.
(fn [& args] (reduce (fn [x y] (if (> x y) x y) ) args ) )

Real error is that you called parameter first - it rebinds real first function to number! Just change name to something other, and your variant will work. Although it maybe better explicitly name function, instead of calling anonymous function, for example, you can declare calc-max as local function using letfn, for example. So your my-max will look like:
(defn my-max [ff & more]
(letfn [(calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x)
(rest x))
:else (calc-max m (rest x))))]
(calc-max ff more)))
Although, I think, that you can write simpler code:
(defn my-max [& more] (reduce max more))

Your function doesn't work because first in fn treated as function and not as input value. So when you write
user=> (my-max 12 3 4 5 612 3)
it's talling that can't cast 12 to function. Simply, it can be rewrited as
(defn my-max1 [fst & more]
((fn calc-max [m x]
(cond (empty? x) m
(> (first x) m) (calc-max (first x) (rest x))
:else (calc-max m (rest x))))
fst more))
or even without fn
(defn my-max [x & xs]
(cond (empty? xs) x
(> (first xs) x) (recur (first xs) (rest xs))
:else (recur x (rest xs))))

To elaborate a little more on the exception that you are seeing: whenever Clojure throws something like
java.lang.Integer cannot be cast to clojure.lang.IFn
at you it means that it tried to call a function but the thing it tried to call was not a function but something else. This usually occurs when you have code like this
(smbl 1 2 3)
If smbl refers to a function, clojure will execute it with parameters 1 2 and 3. But if smbl doesn't refer to a function then you will see an error like the one above. This was my pointer in looking through your code and, as 4e6 pointed out, (first x) is the culprit here because you named your function argument first.

Not as good as the reduce but ok ba:
(fn [& args]
(loop [l args, maxno (first args)]
(if (empty? l)
maxno
(if (> maxno (first l) )
(recur (rest l) maxno)
(recur (rest l) (first l))))))
Can use cond I suppose

Related

Clojure filter method without standard clojure functions

I need to make filter method, but i can't return method name as argument, not as result.
In my case, i need to input odd? method as argument and call recursion.
I can use only this construction:
(defn my-filter [p xn])
My code:
(defn my-filter [p xs]
(if (p (first xs))
(cons (first xs) (recur p (next xs)))
(recur p (next xs) )))
(my-filter odd? '(1 2 3 4 5))
Error: IllegalArgumentException Argument must be an integer: clojure.core/even? (core.clj:1372)
As i can see, where recursion is called, arguments are calculating result, instead of call recursion with odd? and (next xs) arguments
Two issues need attention. Or maybe only one issue, if you don't need to handle very long lists. 1) The function does not notice when the inputs are exhausted. Open a REPL and try (odd? nil) and you will see what happens! 2) If you try the function on a really long list, you might get a StackOverflow. The clojure.org guide for recursion has an example of how to avoid that problem - actually it illustrates solutions to both problems: https://clojure.org/guides/learn/flow#_recursion
Your code does not compile:
Syntax error (UnsupportedOperationException) compiling recur at ... .
Can only recur from tail position
You have to replace the recurs with explicit recursive calls to my-filter:
(defn my-filter [p xs]
(if (p (first xs))
(cons (first xs) (my-filter p (next xs)))
(my-filter p (next xs))))
Now it compiles, but ...
(my-filter odd? [])
Execution error (IllegalArgumentException) at ...
Argument must be an integer:
You need to check that the sequence argument xs is not empty before doing anything else with it:
(defn my-filter [p xs]
(when (seq xs)
(if (p (first xs))
(cons (first xs) (my-filter p (rest xs)))
(my-filter p (rest xs)))))
The when evaluates to nil if the condition fails. The nil, called on to be a sequence, behaves as an empty one. So ...
(my-filter odd? [])
=> nil
(my-filter odd? (range 10))
=> (1 3 5 7 9)
It works. However, it evaluates (first xs) twice, and mentions (my-filter p (rest xs)) twice. Factoring these out, we get
(defn my-filter [p xs]
(when (seq xs)
(let [head (first xs)
tail (my-filter p (rest xs))]
(if (p head) (cons head tail) tail))))
This uses direct recursion. So it runs out of stack on a long sequence:
(count (my-filter odd? (range 10000)))
Execution error (StackOverflowError) at ...
Wrapping the recursion in lazy-seq flattens the evaluation, devolving it to whatever explores the sequence:
(defn my-filter [p xs]
(lazy-seq
(when (seq xs)
(let [head (first xs)
tail (my-filter p (rest xs))]
(if (p head) (cons head tail) tail)))))
Now ...
(count (my-filter odd? (range 10000)))
=> 5000
If you want an eager version, you had better build the returned sequence as a vector:
(defn eager-filter [p coll]
(loop [answer [], coll (seq coll)]
(if-let [[x & xs] coll]
(recur
(if (p x) (conj answer x) answer)
xs)
(sequence answer))))
This won't run out of stack:
(count (eager-filter odd? (range 10000)))
=> 5000
But it can't handle an endless sequence:
(first (eager-filter odd? (range)))
Process finished with exit code 137 (interrupted by signal 9: SIGKILL)
I had to kill the process.
I really like this solution, therefore I share with you. Very simple. (I know, that is not exactly what was the question but different approach.)
(def data (vec (range 10)))
Map implementation
(defn -map [f coll]
(reduce
(fn [acc v]
(conj acc (f v)))
[]
coll))
Filter implementation
(defn -filter [f coll]
(reduce
(fn [acc v]
(if (f v)
(conj acc v))
[]
coll))
Example usage
(->> data
(-map inc)
(-filter odd?))

4clojure: set-intersection, recursive lambda

I am attempting to write a recursive lambda function (accepting two arguments) that finds the intersection between two (potentially) unsorted sets. Here is the code, which I believe most will find straight forward:
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out))))
(inner (rest x) y (cons (first x) out))
(inner a b '[])
)
I hope to use this lambda function intersection in place of the underscore _ that follows:
(= (__ #{0 1 2 3} #{2 3 4 5}) #{2 3})
However, this code fails to compile, insisting that Java is Unable to resolve symbol: inner in this context...
Any suggestions?
source: http://www.4clojure.com/problem/81
You could try :
#(set (filter %1 %2))
Since sets are functions (see another useful example there). The syntax with %1 and %2 is the same as writing :
(fn [s1 s2] (set (filter s1 s2)))
Or even more succinctly :
(comp set filter)
Regarding the inner error, you simply misplaced the parens (but I don't really see the logic otherwise) :
(fn intersection [a b]
(fn inner [x y out]
(if (empty? x) out
(if (nil? (some ((set (first x)) y )))
(inner (rest x) y out)))
(inner (rest x) y (cons (first x) out))
(inner a b '[])))
If you insist on building the set manually (which I did not so long ago), you could end up with something like that :
(fn [s1 s2]
(reduce #(if (contains? s2 %2) (conj %1 %2) %1) #{} s1))
But really the first solution is the most elegant.

Clojure : function returns nil rather an evaluated expression

I have written a function that sums the members of a list. Pretty straightforward, newbie stuff, but for some reason it returns nil, and I am at a loss as to why: this should be a no-brainer. The implementation and function call follow.
The implementation:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 2)
(+ (first x) (first (rest x)) total))
(if (= (count x) 1)
(+ (first x) total))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
The call to the function:
(println "our total is: " (add-list-members '(2 23 33 14 33 134 9000 98993)))
Meanwhile, I have a debugging version with print statements added, and I have been able to verify that the implementation works as it should.
Debugging version:
(defn add-list-members-debug
([x] (add-list-members-debug x 0))
([x total]
(println ">>> our list now: " x)
(println ">>> our total now: " total)
(if (= (count x) 2)
(println "outcome 2 : " (+ (first x) (first (rest x)) total)))
(if (= (count x) 1)
(println "outcome 1 : " (+ (first x) total)))
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total)))))
Call to debugging version:
(add-list-members-debug '(2 23 33 14 33 134 9000 98993))
The development tools I am using are Vim plugged into the Leiningen REPL. Any hints about what I'm doing wrong here would be most appreciated.
You used if in a wrong way. Consider the following code: I intentionally simplified the code to make it clear what happens.
(defn xxx [v]
(if (= (count v) 1) "one")
(if (= (count v) 2) "two")
(if (> (count v) 2) "more"))
What happens if you run (xxx [1])? Perhaps you expect the code will return "one", however, it returns nil. Why?
Function returns value of its last expression, in this case, the last line (if (> (count v) 2) "more"). If you pass [1], the first if expression returns "one", which is ignored. The second if will return nil, which is also ignored. The third and the last will return nil, which is the return value of the function.
Perhaps the simplest way to compute sum of elements is:
(defn add-elements [xs] (apply + xs))
or
(defn add-elements [xs] (reduce + xs))
Your code can be reimplemented in much simpler way:
(defn add-elements
([xs] (add-elements xs 0))
([xs total] (if (empty? xs) total
(recur (rest xs) (+ total (first xs))))))
The parentheses are wrong, or at least suboptimal, and you have no base case that returns total. (About the parentheses: Your indentation, which is correct given the parentheses, shows this: Each if is on the same level; none of them are in the "else" position.) Here's one correct version:
(defn add-list-members
([x] (add-list-members x 0))
([x total]
(if (= (count x) 0)
total
(if (= (count x) 2)
(+ (first x) (first (rest x)) total)
(if (= (count x) 1)
(+ (first x) total)
(if (> (count x) 2)
(recur (rest (rest x)) (+ (+ (first x) (first (rest x))) total))))))))
You get nil as the return value because when the last if test fails, it goes to the else clause, which in this case is an empty end of a list, i.e. nil.
However, the multiple ifs can be replaced with one cond. You can also use ffirst for (first (first, fnext instead of (first (rest, and nnext instead of (rest (rest. It would also be more idiomatic to use a predicate such as empty? instead of checking for count equal to 0; I used count for the base case simply to maintain the parallel with your existing code. The simplest version might be:
(defn add-list-members [x] (apply + x))
You could also use reduce for a very simple version. You may just have wanted to experiment with recur, though.
(Well, you could do it without using the embedded else clauses, as in your original, but I wouldn't recomment it, and you still need the empty sequence base case. When you put multiple separate expressions in an function definition, each one of them always gets executed. This is inefficient and, I feel, error prone. Using multiple, separate expressions in a function definition makes sense when you're creating side effects--e.g. adding print statements for debugging.)

Error with variadic function in Clojure

I am trying to write a custom max function in Clojure, which should support one or more arguments. However, I am running into an error that I cannot figure out. Here is the below function:
(defn my-max [arg & rest]
(loop [m arg c rest]
(cond (empty? c) m
(> m (first c)) (recur m (rest c))
:else (recur (first c) (rest c)))))
And I encounter the following error when attempting to evaluate the function:
user> (my-max 2 3 1 4 5)
ClassCastException clojure.lang.ArraySeq cannot be cast to clojure.lang.IFn user/my-max (NO_SOURCE_FILE:5)
I thought this would work because I was under the assumption that rest was just a sequence. I was able to get this function to work without a variadic signature, where the argument is simply a sequence:
(defn my-max [coll]
(loop [m (first coll) c (rest coll)]
(cond (empty? c) m
(> m (first c)) (recur m (rest c))
:else (recur (first c) (rest c)))))
The problem appears to be a name collision. You have used the name rest for the tail sequence of your calling arguments. Then you subsequently try to use the function rest, but that sequence is seen instead.

Clojure: What is wrong with my implementation of flatten?

I've been working through problems on 4Clojure today, and I ran into trouble on Problem 28, implementing flatten.
There are a couple of definite problems with my code.
(fn [coll]
((fn flt [coll res]
(if (empty? coll)
res
(if (seq? (first coll))
(flt (into (first coll) (rest coll)) res)
(flt (rest coll) (cons (first coll) res))))) coll (empty coll)))
I could use some pointers on how to think about a couple of problems.
How do I make sure I'm not changing the order of the resulting list? cons and conj both add elements wherever it is most efficient to add elements (at the beginning for lists, at the end for vectors, etc), so I don't see how I'm supposed to have any control over this when working with a generic sequence.
How do I handle nested sequences of different types? For instance, an input of '(1 2 [3 4]) will will output ([3 4] 2 1), while an input of [1 2 '(3 4)] will output (4 3 2 1)
Am I even approaching this from the 'right' angle? Should I use a recursive inner function with an accumulator to do this, or am I missing something obvious?
You should try to use HOF (higher order functions) as much as possible: it communicates your intent more clearly and it spares you from introducing subtle low-level bugs.
(defn flatten [coll]
(if (sequential? coll)
(mapcat flatten coll)
(list coll)))
Regarding your questions about lists and vectors. As you might see in tests, output is list. Just make correct abstraction. Fortunately, clojure already has one, called sequence.
All you need is first, rest and some recursive solution.
One possible approach:
(defn flatten [[f & r]]
(if (nil? f)
'()
(if (sequential? f)
(concat (flatten f) (flatten r))
(cons f (flatten r)))))
Here's how to do it in a tail call optimised way, within a single iteration, and using the least amount of Clojure.core code as I could:
#(loop [s % o [] r % l 0]
(cond
(and (empty? s) (= 0 l))
o
(empty? s)
(recur r
o
r
(dec l))
(sequential? (first s))
(recur (first s)
o
(if (= 0 l)
(rest s)
r)
(inc l))
:else
(recur (rest s)
(conj o (first s))
r
l)))