clojure: stack overflow over range - clojure

I am trying to solve problem 60 at 4clojure.com
sequence reductions
my solution works for the last two cases but fails for the first case in handling range.
here is my solution
(fn reds
([func lst](if (empty? lst)
[]
(reds func (first lst) (rest lst))))
([func init lst](if (empty? lst)
(println "hi")
(concat [init] (reds func (func init (first lst)) (rest lst)))))
)
I think this is because I keep calling the function on more terms of an infinite list . but how do I do better?
update : solved it using lazy-seq

Related

How to fix recursive search through list

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"])

CompilerException java.lang.RuntimeException: Unable to resolve symbol: invert-helper in this context

I'm pretty new to closure and I don't understand why I'm getting this error message at runtime. Here is my code:
(defn invert [lst]
(if (empty? lst)
()
(cons (invert-helper lst) (invert (rest lst)))))
(defn invert-helper [lst]
(list (nth lst 1) (first lst)))
This should fix the problem:
(defn invert-helper [lst]
(list (nth lst 1) (first lst)))
(defn invert [lst]
(if (empty? lst)
()
(cons (invert-helper lst) (invert (rest lst)))))
That is: the invert-helper function must be defined before its first use in invert.
Another option, apart from defining all the functions before using them, may be declaring invert-helper before invert:
(declare invert-helper)
(defn invert [lst]
(if (empty? lst)
()
(cons (invert-helper lst) (invert (rest lst)))))
(defn invert-helper [lst]
(list (nth lst 1) (first lst)))
You're also calling (nth lst 1) where lst may have only one element - this will throw an exception.

Clojure Lazy Sequence Issue

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.

Deep-Reverse Clojure

I'm trying to implement deep-reverse in clojure. If lst is (1 (2 (3 4 5)) (2 3)), it should return ((3 2) ((5 4 3) 2) 1). This is what I have so far:
defn dRev [lst]
( if (= lst ())
nil
( if (list? (first lst))
( dRev (first lst) )
( concat
( dRev (rest lst)) (list (first lst))
)
)
)
)
However, my implementation only works if the nested list is the last element, but the resulted list is also flattened.
For eg: (dRev '(1 2 (3 4)) will return (4 3 2 1).
Otherwise, for eg: (dRev '(1 (2 3) 4)) will return (3 2 1) only.
I hit this brick wall for a while now, and I can't find out the problem with my code. Can anyone please help me out?
The other answer gave you the best possible implementation of a deep-reverse in Clojure, because it uses the clojure.walk/postwalk function which generalizes the problem of deep-applying a function to every element of a collection. Here I will instead walk you through the problems of the implementation you posted.
First, the unusual formatting makes it hard to spot what's going on. Here's the same just with fixed formatting:
(defn dRev [lst]
(if (= lst ())
nil
(if (list? (first lst))
(dRev (first lst))
(concat (dRev (rest lst))
(list (first lst))))))
Next, some other small fixes that don't yet fix the behaviour:
change the function name to conform to Clojure conventions (hyphenation instead of camel-case),
use the usual Clojure default name for collection parameters coll instead of lst,
use empty? to check for an empty collection,
return () in the default case because we know we want to return a list instead of some other kind of seq,
and use coll? instead list? because we can just as well reverse any collection instead of just lists:
(If you really want to reverse only lists and leave all other collections as is, reverse the last change.)
(defn d-rev [coll]
(if (empty? coll)
()
(if (coll? (first coll))
(d-rev (first coll))
(concat (d-rev (rest coll))
(list (first coll))))))
Now, the formatting fix makes it obvious what's the main problem with your implementation: in your recursive call ((d-rev (first coll)) resp. (dRev (first lst))), you return only the result of that recursion, but you forget to handle the rest of the list. Basically, what you need to do is handle the rest of the collection always the same and only change how you handle the first element based on whether that first element is a list resp. collection or not:
(defn d-rev [coll]
(if (empty? coll)
()
(concat (d-rev (rest coll))
(list (if (coll? (first coll))
(d-rev (first coll))
(first coll))))))
This is a working solution.
It is terribly inefficient though, because the concat completely rebuilds the list for every element. You can get a much better result by using a tail-recursive algorithm which is quite trivial to do (because it's natural for tail-recursion over a sequence to reverse the order of elements):
(defn d-rev [coll]
(loop [coll coll, acc ()]
(if (empty? coll)
acc
(recur (rest coll)
(cons (if (coll? (first coll))
(d-rev (first coll))
(first coll))
acc)))))
As one final suggestion, here's a solution that's halfways towards the one from the other answer by also solving the problem on a higher level, but it uses only the core functions reverse and map that applies a function to every element of sequence but doesn't deep-recurse by itself:
(defn deep-reverse [coll]
(reverse (map #(if (coll? %) (deep-reverse %) %) coll)))
You can build what you are writing with clojure.walk/postwalk and clojure.core/reverse. This does a depth-first traversal of your tree input and reverses any seq that it finds.
(defn dRev [lst]
(clojure.walk/postwalk #(if (seq? %) (reverse %) %) lst))
Here is my version of the problem, if you enter something like this:
(deep-reverse '(a (b c d) 3))
It returns
=> '(3 (d c b) a)
The problem is taken from Ninety-Nine Lisp Problems
My code ended up like this, though, they might be better implementations, this one works fine.
(defn deep-reverse
"Returns the given list in reverse order. Works with nested lists."
[lst]
(cond
(empty? (rest lst)) lst
(list? (first lst)) (deep-reverse(cons (deep-reverse (first lst)) (deep-reverse (rest lst))))
:else
(concat (deep-reverse (rest lst)) (list (first lst)))))
Hope this is what you were looking for!

Scheme, how to square just negative numbers in a list leaving the rest of the list intact

I have been working on a call to accumulate which goes as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
However when I try to square something by slecting it through filter the answer doesn't work. What I have so far is this:
(define (f2b items)
(accumulate (lambda (x y)
(cons (append
(map square (filter negative? (filter number? x))) x) y)) () items)
)
The Input I give is:
(f2a '(("sdas" 89) (-53 "sad")))
The output I get is:
((sdas 89) (2809 -53 sad))
I can't seem to get the negative number to go away.
It would be much easier to use filter and map. Filter is predefined but it looks like this.
(define (filter1 predicate sequence)
(cond
((null? sequence) null)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
map is also predefined, it just runs a function over a list.
This should be pretty simple to write, but incase you need help you should just write a lamdba for the predicate in filter.
Actually, the functionality you describe is not usually the job of an accumulator. Instead, squaring negative numbers in a list seems like the perfect job for something like a map.
First, let's do:
(define (make-positive x)
(if (and (number? x) (negative? x))
(square x)
x))
Now suppose we want to operate on a list called lst. If it was just a flat list, like '(1 "2" -5 -4 6), then we could just
(map make-positive lst)
Since we need to operate on lists which are nested two levels deep, we could do:
(map (lambda (x)
(map make-positive x))
lst)
If we wanted to operate on lists which are nested arbitrarily deep, we could do:
(define (nested-map fn elm)
(if (list? elm)
(map (lambda (x) (nested-map fn x)) elm)
(fn elm)))
(nested-map make-positive lst)
PS - we can define map like this:
(define (map fn lst)
(if (empty? lst)
'()
(cons (fn (car lst))
(map fn (cdr lst)))))