Singly-linked list (insert [list elt]) function - clojure

I am about to lose my mind if I don't find this bug. I implemented a version of a singly-linked list:
(ns clojure_fun.core)
(defprotocol MConsP
(elt [this] "returns elt")
(cdr [this] "returns cdr")
(set-elt! [this val] "set elt")
(set-cdr! [this val] "set cdr")
)
(deftype MCons [^{:unsynchronized-mutable true} elt
^{:unsynchronized-mutable true} cdr]
MConsP
(elt [this] elt)
(cdr [this] cdr)
(set-elt! [this val] (set! elt val))
(set-cdr! [this val] (set! cdr val))
)
(defn mcons [a b] (MCons. a b))
(defn mlist [& xx]
(if (empty? xx) nil
(mcons (first xx) (apply mlist (rest xx))))
)
(defn insert [xx elt]
(cond (nil? xx) (mcons elt nil)
(< elt (-> xx cdr elt))
(set-cdr! xx (mcons elt (cdr xx)))
:else (insert (cdr xx) elt))
)
(def x (mlist 1 3 4 5 6))
(insert x 2)
When I try to evaluate the last line(insert x 2)I get the following error:
CompilerException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn, compiling:(clojure_fun/core.clj:1:26)
I haven't been so stumped in a long time. Probably because I'm just learning Clojure.
Thanks in advance.

The problem is in the line:
(< elt (-> xx cdr elt))
In your local scope, elt is a long, and you're trying to apply the elt function (now shadowed by the local) to (cdr xx). Just rename the elt argument to something else.

Related

How to rewrite this function to be tail-recursive?

I'm reading the book The Little Schemer, I implement the functions in Clojure, How to rewrite this function as a tail-recursive function in Clojure?
(defn rember*
[a lat]
(cond
(empty? lat) []
(clojure.inspector/atom? (first lat))
(if (= a (first lat))
(rember* a (rest lat))
(cons (first lat)
(rember* a (rest lat))))
:else
(cons (rember* a (first lat))
(rember* a (rest lat)))))
Here is a translation of your code to a version that uses a loop and two lists instead of recursion in order to maintain program state:
(defn rember* [a lat]
(loop [[[op-type a lat] & rest-ops] (list [:rember a lat])
data '()]
(case op-type
nil (first data)
:value (recur rest-ops (cons a data))
:rember (cond
(empty? lat) (recur rest-ops (cons '() data))
(clojure.inspector/atom? (first lat))
(if (= a (first lat))
(recur (cons [:rember a (rest lat)] rest-ops) data)
(recur (into rest-ops [[:cons]
[:rember a (rest lat)]
[:value (first lat)]])
data))
:else (recur (into rest-ops [[:cons]
[:rember a (rest lat)]
[:rember a (first lat)]])
data))
:cons (let [[a b & data] data]
(recur rest-ops (cons (cons b a) data))))))
I agree, loop-recur is the more clojuresk answer!
But for a tail-recursive version, you could also do:
(def atom? (complement coll?))
(defn rember*
([a lat] (rember* a lat []))
([a lat acc]
(cond (empty? lat) (seq acc) ;; or just `acc` when result should be vector
(atom? (first lat)) (if (= a (first lat))
(rember* a (rest lat) acc)
(rember* a (rest lat) (conj acc (first lat))))
:else (rember* a (rest lat) (conj acc (rember* a (first lat)))))))
With this, you can easily build loop-recur by replacing the recursive function call using recur. However note that the last call of rember* cannot be placed by recur - because you cannot nest recur calls.
(defn rember* [a lat]
(loop [a a
lat lat
acc []]
(cond (empty? lat) (seq acc)
(atom? (first lat)) (if (= a (first lat))
(recur a (rest lat) acc)
(recur a (rest lat) (conj acc (first lat))))
:else (recur a (rest lat) (conj acc (rember* a (first lat)))))))

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

Why does clojure give this arity error

I have the function definition below for map-edit
(def map-edit
(fn [m lst k f]
(if (car lst)
(assoc m
(car lst)
(map-edit (get m (car lst) {}) k f))
(assoc m k (f (get m k))))))
When I try to call this function in my repl
(map-edit {} (list "oeu") "oeuoeu" (fn [q] "oeu"))
I get an error for Arity
ArityException Wrong number of args (3) passed to: core/map-edit clojure.lang.AFn.throwArity (AFn.java:429)
Why does it think I am only passing 3 arguments?
; CIDER 0.8.2 (Java 1.8.0_121, Clojure 1.8.0, nREPL 0.2.12)
Assuming that you have these definitions
(def car first)
(def cdr rest)
The recursive call to map-edit only uses 3 arguments
The line probably should be
(map-edit (get m (car lst) {}) (cdr lst) k f))
Note
Assuming that #SultanLegend's answer is correct (not accepted as I write), the core update-in does what you require. You could define ...
(defn map-edit [m lst k f]
(update-in m (conj (vec lst) k) f))
(map-edit {} (list "oeu") "oeuoeu" (fn [q] "oeu"))
=> {"oeu" {"oeuoeu" "oeu"}}

How to delete an element from a nested list?

I have a deeply nested list and I want to delete a given element from all its occurrences in the list. I have this code:
(defn eliminate [value lst]
(defn sub-eliminate [lst]
(def currentItem (first lst))
(if-not (empty? lst)
(if (seq? currentItem)
(cons (sub-eliminate currentItem) (sub-eliminate (rest lst)))
(if (= value currentItem)
(sub-eliminate (rest lst))
(cons currentItem (sub-eliminate (rest lst)))
)
)
'()
)
)
(sub-eliminate lst)
)
But, it doesn't delete at inner levels. Why??
My guess is that you're using vectors as sequences.
(eliminate 3 [3 3])
;()
(eliminate 3 [3 [3]])
;([3])
This would have been trivial to find had you shown us an example: tut, tut!
What's going on?
Although vectors are seqable, they are not sequences:
(seq? [])
;false
At the outer level, you treat lst as a sequence, so first and rest work, since they wrap their argument in an implicit seq. But seq? will fail on any immediately enclosed vector, and those further in won't even be seen.
If you replace seq? with sequential?, lists and vectors will work.
(sequential? [])
;true
More serious, as #noisesmith noted, is your use of def and defn at inner scope. Replace them with let or letfn.
You could also improve your style:
Replace (if-not (empty? lst) ... ) with (if (seq lst) ...).
Use cond to flatten your nested ifs. This requires inverting
the test in (1), so removes the need for it.
Use recur for the tail-recursive case where you find value, as
#Mark does.
If you don't want to see the result, look away now:
(defn eliminate [value lst]
(letfn [(sub-eliminate [lst]
(let [current-item (first lst)]
(cond
(empty? lst) '()
(sequential? current-item) (cons (sub-eliminate current-item)
(sub-eliminate (rest lst)))
(= value current-item) (recur (rest lst))
:else (cons current-item (sub-eliminate (rest lst))))))]
(sub-eliminate lst)))
There is a remaining tender spot:
You invoke (first lst) before you know that lst is not empty. No
harm done: you'll just get nil, which you ignore.
An Alternative Apporach using Destructuring
You can often use destructuring to abbreviate recursive processing of sequences. I'd be inclined to express your function thus:
(defn eliminate [x xs]
((fn rem-x [xs]
(if-let [[y & ys] (seq xs)]
(if (= x y)
(recur ys)
(cons
(if (sequential? y) (rem-x y) y)
(rem-x ys)))
()))
xs))
For the sake of learning take a look at this function:
(define rember*
(lambda (x l)
(cond ((null? l) '())
((atom? (car l))
(if (eq? (car l) x)
(rember* x (cdr l))
(cons (car l)
(rember* x (cdr l)))))
(else (cons (rember* x (car l))
(rember* x (cdr l)))))))
This is a simple recursive function from book 'The Little Schemer', which is a good source to learn how to write such recursive functions.
Let's see if we can translate it into Clojure:
(defn rember* [x l]
(cond (empty? l) '()
(seq? (first l)) (cons (rember* x (first l))
(rember* x (rest l)))
:else (if (= (first l) x)
(recur x (rest l))
(cons (first l)
(rember* x (rest l))))))
user> (rember* 'x '((x y) x (z (((((x))))))))
;; => ((y) (z ((((()))))))
(defn expel [victim xs]
(mapcat (fn [x]
(cond
(sequential? x) [(expel victim x)]
(= x victim) []
:else [x]))
xs))

Trouble with a program

I am doing this problem set in preparation for an exam. It's in the book. Basically it tells us to design a program that counts all occurrences of "hello" in an instance of XEnum.v2.
Everything works perfectly except this problem. I am having problems with this check expect
(check-expect (count-in-xitem xitem3) 3)
it says it expects a non-empty list, but given 'ol. It should absolutely give me 3. Why does it keep telling me it expects a non-empty list? I dumbfounded and can't figure out why.
;; An XEnum.v2 is one of:
;; – (cons 'ol [List-of XItem.v2])
;; – (cons 'ol (cons [List-of Attribute] [List-of XItem.v2]))
;; An XItem.v2 is one of:
;; – (cons 'li (cons XWord empty))
;; – (cons 'li (cons [List-of Attribute] (cons XWord empty)))
;; – (cons 'li (cons XEnum.v2 empty))
;; – (cons 'li (cons [List-of Attribute] (cons XEnum.v2 empty)))
;; A XWord is '(word ((text String)))
;; An Attribute is
;; - (cons Symbol (cons String empty))
(define xword1 '(word ((text "hello"))))
(define xword2 '(word ((text "Hello"))))
(define attr1 (cons 'Symbol (cons "hello" empty)))
(define attr2 (cons 'Symbol (cons "elo" empty)))
(define xitem1 (cons 'li (cons xword1 empty)))
(define xitem2 (cons 'li (cons (list attr1 attr2) (cons xword1 empty))))
(define xe1 (cons 'ol (list xitem1 xitem2))) ;; 3
(define xe2 (cons 'ol (cons (list attr1 attr2) (list xitem2 xitem1))))
(define xitem3 (cons 'li (cons xe1 empty))) ;; 1
(define xitem4 (cons 'li (cons (list attr1 attr2) (cons xe1 empty))))
;; X-Item.v2 -> Number
;; returns number of "hello" occurences in an X-Item.v2
(define (count-in-xitem xi)
(cond
[(is-xword? (second xi)) (count-in-xword (second xi))]
[(is-xenum? xi) (+ (count-in-xitem (second xi))
(count-in-xitem (second (rest xi))))]
[(is-attribute? (first (second xi))) (+ (count-in-loa (second xi))
(count-in-xword (first (rest (rest xi)))))]
[else (+ (count-in-loa (second xi))
(occurrences (second (rest xi))))]))
;; tests for count-in-xitem function
;(check-expect (count-in-xitem xitem1) 1)
;(check-expect (count-in-xitem xitem2) 2)
;(check-expect (count-in-xitem xe1) 3)
(check-expect (count-in-xitem xitem3) 3)
;; XWord -> Natural
;; returns 1 if string is "hello"
(define (count-in-xword x)
(if (string=? (second (first (first (rest x))))
"hello")
1
0))
;; tests for count-in-xword function
(check-expect (count-in-xword xword1) 1)
(check-expect (count-in-xword xword2) 0)
;; [List-of Attribute] -> Natural
;; returns 1 if occurrences of "hello" in the list of attributes
(define (count-in-loa loa)
(foldr (λ(s b) (if (string=? (second s) "hello") (+ 1 b) b)) 0 loa))
;; tests for count-in-loa function
(check-expect (count-in-loa (list attr2)) 0)
(check-expect (count-in-loa (list attr1
(cons 'b (cons "hello" empty)))) 2)
;; XEnum.v2 -> Number
;; counts all occurrences of "hello" in an instance of XEnum.v2
(define (occurrences xe)
(if (eqv? (rest (rest xe)) empty)
(xenum2 empty (rest xe))
(xenum2 (second xe) (rest (rest xe)))))
;; [List-of Attribute] [List-of XItem.v2] -> Number
;; returns number of "hello" occurences
(define (xenum2 atr item)
(+ (count-in-loa atr)
(count-in-xitem item)))
;; tests for xenum2 function
;(check-expect (xenum2 (list attr1 attr2) (list xitem1 xitem2)) 0)
;; [List-of Any] -> Boolean
;; checks if the list is an XEnum.v2
(define (is-xenum? xe)
(cond
[(empty? xe) false]
[(symbol? (first xe))
(symbol=? (first xe) 'ol)]))
;; tests for is-attribute? function
(check-expect (is-xenum? xe1) true)
(check-expect (is-xenum? xe2) true)
(check-expect (is-xenum? (cons 'al (list xitem1 xitem2))) false)
(check-expect (is-xenum? empty) false)
;; ATTRIBUTE
(define (is-attribute? xe)
(and (symbol? (first xe))
(string? (second xe))
(not (symbol=? (first xe) 'ol))))
;; tests for is-attribute? function
(check-expect (is-attribute? attr1) true)
(check-expect (is-attribute? attr2) true)
(check-expect (is-attribute? (cons 1 (cons "hi" empty))) false)
;; XWORD
(define (is-xword? xe)
(and (symbol? (first xe))
(symbol=? 'word (first xe))
(symbol=? 'text (first (first (second '(word ((text String)))))))
(symbol=? 'String (second (first (second '(word ((text String)))))))))
;; tests for is-xword? function
(check-expect (is-xword? xword1) true)
(check-expect (is-xword? xword2) true)
(check-expect (is-xword? '(world ((text "hello")))) false)
I think the problem is here
;; ATTRIBUTE
(define (is-attribute? xe)
(and (symbol? (first xe))
(string? (second xe))
(not (symbol=? (first xe) 'ol))))
It looks like you can track this problem down using the stepper.
Click the "step" button, and wait until all of the steps have been computed (you'll see the denominator stop changing in the step count). Then, choose "jump to end" from the drop-down menu. You'll see that your test case is asking for (first 'ol). To see how this arises, step backward; I can see that you're calling is-attribute? on 'ol, but I didn't step any further back to see why this was the case.