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.
Related
problem formulation
Informally speaking, I want to write a function which, taking as input a function that generates binary factorizations and an element (usually neutral), creates an arbitrary length factorization generator. To be more specific, let us first define the function nfoldr in Clojure.
(defn nfoldr [f e]
(fn rec [n]
(fn [s]
(if (zero? n)
(if (empty? s) e)
(if (seq s)
(if-some [x ((rec (dec n)) (rest s))]
(f (list (first s) x))))))))
Here nil is used with the meaning "undefined output, input not in function's domain". Additionally, let us view the inverse relation of a function f as a set-valued function defining inv(f)(y) = {x | f(x) = y}.
I want to define a function nunfoldr such that inv(nfoldr(f , e)(n)) = nunfoldr(inv(f) , e)(n) when for every element y inv(f)(y) is finite, for each binary function f, element e and natural number n.
Moreover, I want the factorizations to be generated as lazily as possible, in a 2-dimensional sense of laziness. My goal is that, when getting some part of a factorization for the first time, there does not happen (much) computation needed for next parts or next factorizations. Similarly, when getting one factorization for the first time, there does not happen computation needed for next ones, whereas all the previous ones get in effect fully realized.
In an alternative formulation we can use the following longer version of nfoldr, which is equivalent to the shorter one when e is a neutral element.
(defn nfoldr [f e]
(fn [n]
(fn [s]
(if (zero? n)
(if (empty? s) e)
((fn rec [n]
(fn [s]
(if (= 1 n)
(if (and (seq s) (empty? (rest s))) (first s))
(if (seq s)
(if-some [x ((rec (dec n)) (rest s))]
(f (list (first s) x)))))))
n)))))
a special case
This problem is a generalization of the problem of generating partitions described in that question. Let us see how the old problem can be reduced to the current one. We have for every natural number n:
npt(n) = inv(nconcat(n)) = inv(nfoldr(concat2 , ())(n)) = nunfoldr(inv(concat2) , ())(n) = nunfoldr(pt2 , ())(n)
where:
npt(n) generates n-ary partitions
nconcat(n) computes n-ary concatenation
concat2 computes binary concatenation
pt2 generates binary partitions
So the following definitions give a solution to that problem.
(defn generate [step start]
(fn [x] (take-while some? (iterate step (start x)))))
(defn pt2-step [[x y]]
(if (seq y) (list (concat x (list (first y))) (rest y))))
(def pt2-start (partial list ()))
(def pt2 (generate pt2-step pt2-start))
(def npt (nunfoldr pt2 ()))
I will summarize my story of solving this problem, using the old one to create example runs, and conclude with some observations and proposals for extension.
solution 0
At first, I refined/generalized the approach I took for solving the old problem. Here I write my own versions of concat and map mainly for a better presentation and, in the case of concat, for some added laziness. Of course we can use Clojure's versions or mapcat instead.
(defn fproduct [f]
(fn [s]
(lazy-seq
(if (and (seq f) (seq s))
(cons
((first f) (first s))
((fproduct (rest f)) (rest s)))))))
(defn concat' [s]
(lazy-seq
(if (seq s)
(if-let [x (seq (first s))]
(cons (first x) (concat' (cons (rest x) (rest s))))
(concat' (rest s))))))
(defn map' [f]
(fn rec [s]
(lazy-seq
(if (seq s)
(cons (f (first s)) (rec (rest s)))))))
(defn nunfoldr [f e]
(fn rec [n]
(fn [x]
(if (zero? n)
(if (= e x) (list ()) ())
((comp
concat'
(map' (comp
(partial apply map)
(fproduct (list
(partial partial cons)
(rec (dec n))))))
f)
x)))))
In an attempt to get inner laziness we could replace (partial partial cons) with something like (comp (partial partial concat) list). Although this way we get inner LazySeqs, we do not gain any effective laziness because, before consing, most of the computation required for fully realizing the rest part takes place, something that seems unavoidable within this general approach. Based on the longer version of nfoldr, we can also define the following faster version.
(defn nunfoldr [f e]
(fn [n]
(fn [x]
(if (zero? n)
(if (= e x) (list ()) ())
(((fn rec [n]
(fn [x] (println \< x \>)
(if (= 1 n)
(list (list x))
((comp
concat'
(map' (comp
(partial apply map)
(fproduct (list
(partial partial cons)
(rec (dec n))))))
f)
x))))
n)
x)))))
Here I added a println call inside the main recursive function to get some visualization of eagerness. So let us demonstrate the outer laziness and inner eagerness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
(() () () () (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
< (0 1 2) >
()
solution 1
Then I thought of a more promising approach, using the function:
(defn transpose [s]
(lazy-seq
(if (every? seq s)
(cons
(map first s)
(transpose (map rest s))))))
To get the new solution we replace the previous argument in the map' call with:
(comp
(partial map (partial apply cons))
transpose
(fproduct (list
repeat
(rec (dec n)))))
Trying to get inner laziness we could replace (partial apply cons) with #(cons (first %) (lazy-seq (second %))) but this is not enough. The problem lies in the (every? seq s) test inside transpose, where checking a lazy sequence of factorizations for emptiness (as a stopping condition) results in realizing it.
solution 2
A first way to tackle the previous problem that came to my mind was to use some additional knowledge about the number of n-ary factorizations of an element. This way we can repeat a certain number of times and use only this sequence for the stopping condition of transpose. So we will replace the test inside transpose with (seq (first s)), add an input count to nunfoldr and replace the argument in the map' call with:
(comp
(partial map #(cons (first %) (lazy-seq (second %))))
transpose
(fproduct (list
(partial apply repeat)
(rec (dec n))))
(fn [[x y]] (list (list ((count (dec n)) y) x) y)))
Let us turn to the problem of partitions and define:
(defn npt-count [n]
(comp
(partial apply *)
#(map % (range 1 n))
(partial comp inc)
(partial partial /)
count))
(def npt (nunfoldr pt2 () npt-count))
Now we can demonstrate outer and inner laziness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
(< (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
()
However, the dependence on additional knowledge and the extra computational cost make this solution unacceptable.
solution 3
Finally, I thought that in some crucial places I should use a kind of lazy sequences "with a non-lazy end", in order to be able to check for emptiness without realizing. An empty such sequence is just a non-lazy empty list and overall they behave somewhat like the lazy-conss of the early days of Clojure. Using the definitions given below we can reach an acceptable solution, which works under the assumption that always at least one of the concat'ed sequences (when there is one) is non-empty, something that holds in particular when every element has at least one binary factorization and we are using the longer version of nunfoldr.
(def lazy? (partial instance? clojure.lang.IPending))
(defn empty-eager? [x] (and (not (lazy? x)) (empty? x)))
(defn transpose [s]
(lazy-seq
(if-not (some empty-eager? s)
(cons
(map first s)
(transpose (map rest s))))))
(defn concat' [s]
(if-not (empty-eager? s)
(lazy-seq
(if-let [x (seq (first s))]
(cons (first x) (concat' (cons (rest x) (rest s))))
(concat' (rest s))))
()))
(defn map' [f]
(fn rec [s]
(if-not (empty-eager? s)
(lazy-seq (cons (f (first s)) (rec (rest s))))
())))
Note that in this approach the input function f should produce lazy sequences of the new kind and the resulting n-ary factorizer will also produce such sequences. To take care of the new input requirement, for the problem of partitions we define:
(defn pt2 [s]
(lazy-seq
(let [start (list () s)]
(cons
start
((fn rec [[x y]]
(if (seq y)
(lazy-seq
(let [step (list (concat x (list (first y))) (rest y))]
(cons step (rec step))))
()))
start)))))
Once again, let us demonstrate outer and inner laziness.
user=> (first ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
(< (0 1 2) >
() < (0 1 2) >
() < (0 1 2) >
() () (0 1 2))
user=> (ffirst ((npt 5) (range 3)))
< (0 1 2) >
< (0 1 2) >
()
To make the input and output use standard lazy sequences (sacrificing a bit of laziness), we can add:
(defn lazy-end->eager-end [s]
(if (seq s)
(lazy-seq (cons (first s) (lazy-end->eager-end (rest s))))
()))
(defn eager-end->lazy-end [s]
(lazy-seq
(if-not (empty-eager? s)
(cons (first s) (eager-end->lazy-end (rest s))))))
(def nunfoldr
(comp
(partial comp (partial comp eager-end->lazy-end))
(partial apply nunfoldr)
(fproduct (list
(partial comp lazy-end->eager-end)
identity))
list))
observations and extensions
While creating solution 3, I observed that the old mechanism for lazy sequences in Clojure might not be necessarily inferior to the current one. With the transition, we gained the ability to create lazy sequences without any substantial computation taking place but lost the ability to check for emptiness without doing the computation needed to get one more element. Because both of these abilities can be important in some cases, it would be nice if a new mechanism was introduced, which would combine the advantages of the previous ones. Such a mechanism could use again an outer LazySeq thunk, which when forced would return an empty list or a Cons or another LazySeq or a new LazyCons thunk. This new thunk when forced would return a Cons or perhaps another LazyCons. Now empty? would force only LazySeq thunks while first and rest would also force LazyCons. In this setting map could look like this:
(defn map [f s]
(lazy-seq
(if (empty? s) ()
(lazy-cons
(cons (f (first s)) (map f (rest s)))))))
I have also noticed that the approach taken from solution 1 onwards lends itself to further generalization. If inside the argument in the map' call in the longer nunfoldr we replace cons with concat, transpose with some implementation of Cartesian product and repeat with another recursive call, we can then create versions that "split at different places". For example, using the following as the argument we can define a nunfoldm function that "splits in the middle" and corresponds to an easy-to-imagine nfoldm. Note that all "splitting strategies" are equivalent when f is associative.
(comp
(partial map (partial apply concat))
cproduct
(fproduct (let [n-half (quot n 2)]
(list (rec n-half) (rec (- n n-half))))))
Another natural modification would allow for infinite factorizations. To achieve this, if f generated infinite factorizations, nunfoldr(f , e)(n) should generate the factorizations in an order of type ω, so that each one of them could be produced in finite time.
Other possible extensions include dropping the n parameter, creating relational folds (in correspondence with the relational unfolds we consider here) and generically handling algebraic data structures other than sequences as input/output. This book, which I have just discovered, seems to contain valuable relevant information, given in a categorical/relational language.
Finally, to be able to do this kind of programming more conveniently, we could transfer it into a point-free, algebraic setting. This would require constructing considerable "extra machinery", in fact almost making a new language. This paper demonstrates such a language.
I'm currently trying to learn Clojure. But I am having trouble creating a function that recursively searches through each element of the list and returns the number of "a"'s present in the list.
I have already figured out how to do it iteratively, but I am having trouble doing it recursively. I have tried changing "seq" with "empty?" but that hasn't worked either.
(defn recursive-a [& lst]
(if (seq lst)
(if (= (first lst) "a")
(+ 1 (recursive-a (pop (lst))))
(+ 0 (recursive-a (pop (lst)))))
0))
Welcome to stack overflow community.
You code is fine, except that you made a few minor mistakes.
Firstly, there is one extra pair of braces around your lst parameter that you forward to recursive function. In LISP languages, braces mean evaluation of function. So, first you should remove those.
Second thing is the & parameter syntactic sugar. You do not want to use that until you are certain how it affects your code.
With these changes, the code is as follows:
(defn recursive-a [lst]
(if (seq lst)
(if (= (first lst) "a")
(+ 1 (recursive-a (pop lst)))
(+ 0 (recursive-a (pop lst))))
0))
(recursive-a (list "a" "b" "c"))
You can run it in a web environment: https://repl.it/languages/clojure
Welcome to Stack Overflow.
By invoking recursive-a explicitly the original implementation consumes stack with each recursion. If a sufficiently large list is provided as input this function will eventually exhaust the stack and crash. There are a several ways to work around this.
One of the classic Lisp-y methods for handling situations such as this is to provide a second implementation of the function which passes the running count as an input argument to the "inner" function:
(defn recursive-a-inner [cnt lst]
(cond
(seq lst) (cond
(= (first lst) "a") (recur (inc cnt) (rest lst))
:else (recur cnt (rest lst)))
:else cnt))
(defn recursive-a [& lst]
(recursive-a-inner 0 lst))
By doing this the "inner" version allows the recursion to be pushed into tail position so that Clojure's recur keyword can be used. It's not quite as clean an implementation as the original but it has the advantage that it won't blow up the stack.
Another method for handling this is to use Clojure's loop-ing, which allows recursion within the body of a function. The result is much the same as the "inner" function above:
(defn recursive-a [& lp]
(loop [cnt 0
lst lp]
(cond
(seq lst) (cond
(= (first lst) "a") (recur (inc cnt) (rest lst))
:else (recur cnt (rest lst)))
:else cnt)))
And if we drop the requirement for explicit recursion we can make this a bit simpler:
(defn not-recursive-a [& lst]
(apply + (map #(if (= % "a") 1 0) lst)))
Best of luck.
In the spirit of learning:
You can use & or not. Both are fine. The difference is how you would then call your function, and you would have to remember to use apply when recurring.
Also, simply use first and rest. They are both safe and will work on both nil and empty lists, returning nil and empty list respectively:
(first []) ;; -> nil
(first nil) ;; -> nil
(rest []) ;; -> ()
(rest nil) ;; -> ()
So here is how I would re-work your idea:
;; With '&'
(defn count-a [& lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(apply count-a (rest lst))) ;; use 'apply' here
0))
;; call with variable args, *not* a list
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(if-let [a (first lst)]
(+ (if (= a "a") 1 0)
(count-a (rest lst)))
0))
;; call with a single arg: a vector (could be a list or other )
(count-a ["a" "b" "a" "c"])
However, these are not safe, because they don't use tail-recursion, and so if your list is large, you will blow your stack!
So, we use recur. But if you don't want to define an additional "helper" function, you can instead use loop as the "recur" target:
;; With '&'
(defn count-a [& lst]
(loop [c 0 lst lst] ;; 'recur' will loop back to this point
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(loop [c 0 lst lst]
(if-let [a (first lst)]
(recur (if (= a "a") (inc c) c) (rest lst))
c)))
(count-a ["a" "b" "a" "c"])
All that being said, this is the one I also would use:
;; With '&'
(defn count-a [& lst]
(count (filter #(= % "a") lst)))
(count-a "a" "b" "a" "c")
;; Without '&'
(defn count-a [lst]
(count (filter #(= % "a") lst)))
(count-a ["a" "b" "a" "c"])
I'm working on 4clojure problems and a similar issue keeps coming up. I'll write a solution that works for all but one of the test cases. It's usually the one that is checking for lazy evaluation. The solution below works for all but the last test case. I've tried all kinds of solutions and can't seem to get it to stop evaluating until integer overflow. I read the chapter on lazy sequences in Joy of Clojure, but I'm having a hard time implementing them. Is there a rule of thumb I'm forgetting, like don't use loop or something like that?
; This version is non working at the moment, will try to edit a version that works
(defn i-between [p k coll]
(loop [v [] coll coll]
(let [i (first coll) coll (rest coll) n (first coll)]
(cond (and i n)
(let [ret (if (p i n) (cons k (cons i v)) (cons i v))]
(recur ret coll))
i
(cons i v )
:else v))))
Problem 132
Ultimate solution for those curious:
(fn i-between [p k coll]
(letfn [(looper [coll]
(if (empty? coll) coll
(let [[h s & xs] coll
c (cond (and h s (p h s))
(list h k )
(and h s)
(list h )
:else (list h))]
(lazy-cat c (looper (rest coll))))
))] (looper coll)))
When I think about lazy sequences, what usually works is thinking about incremental cons'ing
That is, each recursion step only adds a single element to the list, and of course you never use loop.
So what you have is something like this:
(cons (generate first) (recur rest))
When wrapped on lazy-seq, only the needed elements from the sequence are realized, for instance.
(take 5 (some-lazy-fn))
Would only do 5 recursion calls to realize the needed elements.
A tentative, far from perfect solution to the 4clojure problem, that demonstrates the idea:
(fn intercalate
[pred value col]
(letfn [(looper [s head]
(lazy-seq
(if-let [sec (first s)]
(if (pred head sec)
(cons head (cons value (looper (rest s) sec)))
(cons head (looper (rest s) sec)))
(if head [head] []))))]
(looper (rest col) (first col))))
There, the local recursive function is looper, for each element tests if the predicate is true, in that case realizes two elements(adds the interleaved one), otherwise realize just one.
Also, you can avoid recursion using higher order functions
(fn [p v xs]
(mapcat
#(if (p %1 %2) [%1 v] [%1])
xs
(lazy-cat (rest xs) (take 1 xs))))
But as #noisesmith said in the comment, you're just calling a function that calls lazy-seq.
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)))
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