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))
Related
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)))))))
I am trying to define the rule 3 of "MIU System" of "Gödel, Escher, Bach" (Douglas Hofstadter), which says:
Replace any III with a U
Example:
MIIIIU → MUIU and MIIIIU → MIUU
Main code:
(define (rule-tree lst)
(if (<= 3 (counter lst #\I))
(append (delete #\I lst) (list #\U))
(append lst empty)))
(define (delete x lst)
(cond [(empty? lst) lst]
[(eq? (first lst) x) (delete x (rest lst))]
[else (append (list (first lst)) (delete x (rest lst)))]))
(define (counter lst target)
(if (empty? lst)
0
(+ (counter (rest lst) target)
(let ((x (first lst)))
(if (list? x)
(counter x target)
(if (eqv? x target) 1 0))))))
With this expression there is no problem:
>(rule-tree '(#\M #\I #\I #\I))
'(#\M #\U)
But I don't know how to determine the position that the "U" should take when finding the 3 "I".
Any suggestion will be very helpful :)
Here is an alternative recursive version, where repl2 encodes the information “we have just encountered one #\I”, while repl3 encodes the information “we have just encountered two #\I”:
(define (repl lst)
(cond ((empty? lst) lst)
((eqv? (first lst) #\I) (repl2 (rest lst)))
(else (cons (first lst) (repl (rest lst))))))
(define (repl2 lst)
(cond ((empty? lst) (list #\I))
((eqv? (first lst) #\I) (repl3 (rest lst)))
(else (cons #\I (cons (first lst) (repl (rest lst)))))))
(define (repl3 lst)
(cond ((empty? lst) (list #\I #\I))
((eqv? (first lst) #\I) (cons #\U (repl (rest lst))))
(else (cons #\I (cons #\I (cons (first lst) (repl (rest lst))))))))
Of course this solution is some kind of hack and cannot scale to a greater number of repetitions. But looking at the structure of this solution and simply generalizing the three functions we can produce a general solution:
(define (repl lst n from to)
(define (helper lst k)
(cond ((empty? lst) (repeat from (- n k)))
((eqv? (first lst) from)
(if (= k 1)
(cons to (helper (rest lst) n))
(helper (rest lst) (- k 1))))
(else (append (repeat from (- n k))
(cons (first lst) (helper (rest lst) n))))))
(define (repeat x n)
(if (= n 0)
'()
(cons x (repeat x (- n 1)))))
We define a function repl that takes a list, the number of copies to replace (n), the element to replace (from) and the element that must be substituted (to). Then we define a helper function to do all the work, and that has as parameters the list to be processed and the number of copies that must be still found (k).
Each time the function encounters a copy it checks if we have finished with the number of copies and substitutes the element, restarting its work, otherwise it decrements the number of copies to find and continues.
If it founds an element different from from it recreates the list with the elements “consumed” until this point (maybe 0) with repeat and then continues its work.
Note that the previous version of the helper function had an error in the final case, when lst is null. Instead of returning simply the empty list, we must return the possibly skipped from elements.
This function reads in a list and swaps values, but only when there's a key in the hash table that matches an element in the list. However, the list that is read in could contain other lists, and I want to check this recursively. I use if (list? elementInList) to determine whether I'm dealing with a list, so I can search that list for elements that may need to be swapped using a recursive call. I tried to do this but it's not handling the lists within the list correctly. What am I doing wrong?
(define (let-helper L)
(map (lambda (x) (swap x (hash-ref *variable-table* x) L))
(filter (lambda (x)
(if (list? x)
(let-helper x) ;; recursion here
(hash-has-key? *variable-table* x)))
L)))
I'd suggest just flattening the list so that you can continue to use map and filter like this:
(define (let-helper L)
(map (lambda (x) (swap x (hash-ref *variable-table* x) L))
(filter (lambda (x) (hash-has-key? *variable-table* x))
(flatten L))))
Otherwise to get it to work would require writing it without map and filter like this:
(define (let-helper L)
(let ((action (lambda (x) (swap x (hash-ref *variable-table* x) L)))
(predicate (lambda (x) (hash-has-key? *variable-table* x))))
(let loop ((a '()) (L L))
(if (null? L)
(reverse a)
(if (list? (car L))
(loop (cons (let-helper (car L)) a) (cdr L))
(if (predicate (car L))
(loop (cons (action (car L)) a) (cdr L))
(loop a (cdr L))))))
Untested.
So the swap should only occur if the hash has the key but the returned list should still have the elements that weren't swapped? If so then not removing the element from the list of it isn't a key would fix that like this:
(define (let-helper L)
(map (lambda (x)
(if (list? x)
(let-helper x)
(if (hash-has-key? *variable-table* x)
(swap x (hash-ref *variable-table* x) L)
x))))
L)
Or
(define (let-helper L)
(let ((action (lambda (x) (swap x (hash-ref *variable-table* x) L)))
(predicate (lambda (x) (hash-has-key? *variable-table* x))))
(let loop ((a '()) (L L))
(if (null? L)
(reverse a)
(if (list? (car L))
(loop (cons (let-helper (car L)) a) (cdr L))
(if (predicate (car L))
(loop (cons (action (car L)) a) (cdr L))
(loop (cons (car L) a) (cdr L))))))
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.
I ran into this error when I try to evaluate the last line below: "No message. [Thrown class java.lang.NullPointerException]"
(defn my-insertion-sort [lst]
(loop [list lst result '()]
(if-not (seq? list) result
(recur (rest list) (my-insert (first list) result)))))
(defn my-insert [n lst]
(cond (nil? lst) (list n)
(> (first lst) n) (conj lst n)
:else
(conj (my-insert n (rest lst)) (first lst))))
(my-insertion-sort '(2 1 3))
Where goes wrong with "my-insertion-sort" function?
(defn my-insertion-sort [lst]
(loop [list lst result '()]
(if (empty? list) result
(recur (rest list) (my-insert (first list) result)))))
(defn my-insert [n lst]
(cond
(empty? lst) (list n)
(> (first lst) n) (conj lst n)
:else (conj (my-insert n (rest lst)) (first lst))))