LISP cdr function - lisp

If I do
(setq x '(NOT (NOT (NOT (NOT A)))) )
(cdr x) is (NOT (NOT (NOT A))))
but (cdr (cdr x)) is NIL
What's going on here?

Um, it shouldn't. (cdr x) should give you '((NOT (NOT (NOT A)))).
Which means (NOT (NOT (NOT A))) is the first element of (cdr x). When you cdr again it's on a one-element list, so you get nil '()

Related

Delete element from a nested list while keeping the original nested structure CLISP [duplicate]

I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)

Removing from nested lists

I've got a homework assignment that has stumped me! I have to create a function goo(A L) that will remove every A in L and it has to work on nested lists also.
Here's what I've got so far
(defun goo(A L)
(cond ((null L) nil) ; if list is null, return nil
(T ; else list is not null
(cond ((atom (car L))) ;if car L is an atom
((cond ((equal A (car L)) (goo A (cdr L))) ;if car L = A, call goo A cdr L
(T (cons (car L) (goo A (cdr L)))))) ;if car L != A,
(T (cons (goo A (car L)) (goo A (cdr L)))))) ;else car L is not atom, call goo on car L and call goo on cdr L
))
This function returns True no matter what I give it.
You parens are messed up. Move the last paren around (atom (car L)) to include the next cond expression. I suggest using an IDE which shows matching parens.
As for styling, if you didn't know, cond can accept multiple clauses. This way you don't need to have the t and then the cond again. You can also use 'if' if you are only testing a single predicate and making a decision based solely on that.
Note: this was originally posted as an edit to the question by the original asker in revision 2.
I tried another approach and it's working now.
(defun goo(A L)
(cond ((null L) nil)
((atom (car L)) (cond ((equal A (car L)) (goo A (cdr L)))
(T (cons (car L) (goo A (cdr L))))))
(T (cons (goo A (car L)) (goo A (cdr L))))
))
Note 2: this should conventionally be formatted like this to show the program structure:
(defun goo (a l)
(cond ((null l) nil)
((atom (car l))
(cond ((equal a (car l))
(goo a (cdr l)))
(t (cons (car l)
(goo a (cdr l))))))
(t (cons (goo a (car l))
(goo a (cdr l))))))
I think it might be easier to look at this a replacement into trees problem. It's easy to define a function that takes a tree and replaces subtrees in it that satisfy a test. There's a standard function subst-if that does that, but it replaces every matching subtree with the same thing. It will be more useful to us if we replace the element with a value computed from the subtree:
(defun %subst-if (new test tree)
"Replace subtrees of TREE that satisfy TEST with the result
of calling NEW with the subtree."
(cond
;; If tree satifies the test, return (new tree).
((funcall test tree)
(funcall new tree))
;; If tree is a cons, recurse.
((consp tree)
(cons (%subst-if new test (car tree))
(%subst-if new test (cdr tree))))
;; Otherwise, just return the leaf.
(tree)))
With this, its easy to define the kind of function we need. When an element X appears somewhere in a nested list structure, it means that there is a cons cell whose car is X. We want to replace that cons cell with its cdr, but to also recurse on the cdr of the cell. This isn't hard:
(defun replace* (x list &key (test 'eql))
"Remove occurrences of X in LIST and its sublists."
(%subst-if
(lambda (cons)
"Replace elements of the form (X . more) with
(replace* x more :test test)."
(replace* x (cdr cons) :test test))
(lambda (subtree)
"Detect subtrees of the form (X . more)."
(and (consp subtree)
(funcall test x (car subtree))))
list))
(replace* 'a '(1 a (2 a 3) a 4 a 5))
;=> (1 (2 3) 4 5)

Why does replacing "(null x)" with "(null (cdr x))" make this code work?

I'm a newbie in LISP. I'm trying to write a bubble sort function in LISP.
This is what I've done so far.
(defun mysort (x)
(if (null x) x
(if (< (car x) (cadr x))
(cons (car x) (mysort (cdr l)))
(cons (cadr x) (mysort (cons (car x) (cddr x)))))))
I'm getting an error
NIL is not a real number
When I modified the code like (after referring several codes)-
(defun mysort (x)
(if (null (cdr x)) x
(if (< (car x) (cadr x))
(cons (car x) (mysort (cdr l)))
(cons (cadr x) (mysort (cons (car x) (cddr x)))))))
Now it works fine.
Why does replacing
(if (null x) x...)
with
(if (null (cdr x)) x...)
make a difference?
Also, I'm calling mysort from another function to run it (length x) number of times. Is it possible to achieve complete sorting in a single recursive loop, only using the basic functions?
If you want to see if the first element is smaller than the second element, then the list needs to have at least two elements.
If there is only one element, CADR returns NIL. This is not a number.
CL-USER 18 > (cadr '(1))
NIL
Your Lisp system should not only tell you the error, but also the function where it occurred. Here: the function <.
Using (null (cdr list)) is a good way to test if there is a second element. A typical error would be to call LENGTH, which is inefficient.
To do a comparison you need at least two elements so checking if x is NIL is not enough.
Checking if (cdr x) is NIL is a nice way to check that the list length is at least two because NIL is special and even if it's not a cons cell it's guaranteed that (cdr NIL) is NIL.
The error you were getting is because NIL is not a number thus you cannot compare with < a number with it and this was happening when executing (< (car x) (cadr x)) when x was a list with a single element.
About sorting in a single recursive call you could use this definition of sorting:
an empty list is sorted
a non-empty list is sorted if the first element is the minimum of the list and the rest of the list is sorted.
This leads to
(defun mysort (x)
(if x
(let ((minimum (reduce #'min x)))
(cons minimum
(mysort (remove minimum x :count 1))))))
That, by the way, is a very inefficient way to do the sorting.

Issue using cons function in Lisp?

I am learning Lisp and I had to write a function whose return value was a list containing the odd integers (if any) from the given input. In code I have this:
(defun f3 (a)
(cond
((null a) nil )
((and (numberp (car a)) (oddp (car a))) (cons (car a) (f3 (cdr a))))
(T (f3 (cdr a)))
) ; end cond
)
I originally wanted to use the append function, but I kept getting errors.
It was recommended to me to use cons function. When I did this my function started working (code is above). I originally had this:
(defun f3 (a)
(cond
((null a) ())
((and (numberp (car a)) (oddp (car a))) (append (f3 (cdr a)) (car a))))
(T (append () (f3 (cdr a))))
)
)
but kept getting errors. For example, if I called (f3 '(1 2 3)) it would say "error 3 is not type LIST". So, my questions are why does cons work here and why did append not work? How does cons work? Thanks in advance.
append wants list arguments, and (car a) is not a list. Instead of (car a) you'd need (list (car a)). In other words, (append (f3 (cdr a)) (list (car a))).
That will basically work, but you'll get the result in reverse order. So that should be (append (list (car a)) (f3 (cdr a))).
Also note that your (append () (f3 (cdr a))) is equivalent to just (f3 (cdr a)).
The resulting changes in your original would be:
(defun f3 (a)
(cond
((null a) ())
((and (numberp (car a)) (oddp (car a)))
(append (list (car a)) (f3 (cdr a)))))
(T (f3 (cdr a)))))
But, you wouldn't normally use append to prepend a single element to a list. It would more naturally be done using cons. So
(append (list (car a)) (f3 (cdr a)))
Is more appropriately done by:
(cons (car a) (f3 (cdr a)))
Which finally takes you right to the working version you showed.
While something like mbratch's answer will help you in learning about list manipulation (and so is probably a more useful answer for you at this point in your study), it's also important to learn about the standard library of the language that you're using. In this case, you're trying to filter out everything except odd numbers. Using remove-if-not, that's just:
(defun keep-odd-numbers (list)
(remove-if-not (lambda (x)
(and (numberp x) (oddp x)))
list))
CL-USER> (keep-odd-numbers '(1 a 2 b 3 c 4 d 5 e))
;=> (1 3 5)
While this isn't a fix to your actual problem, which #mbratch provided, here's the way I would implement something like this using the LOOP macro (another part of the standard library):
(defun keep-odd-numbers (list)
(loop for x in list collecting x when (and (numberp x) (oddp x))))

Checking for Proper Subsets

I need a function that can check if a list a is a proper subset of a list b. My code so far is:
(defun proper-subset (a b)
(cond
(( or (null b)(null b)) nil)
((equal a b) nil)
((find (car a) b) (proper-subset (cdr a) b))
)
)
find checks that each element of a is in b. I know the null arguments need some work as well, but I am trying to figure out how to determine when every element of a is found in b and b has another element. There are built in functions that can make this a lot easier however this a homework question so I have to write my own. Any hints or suggestions would be greatly appreciated.
Common Lisp defines a number of functions for working with lists as sets, so you don't need to write your own. In particular, the useful functions appear at the bottom of The Conses Dictionary. The particularly useful ones are
set-difference, nset-difference
set-exclusive-or, nset-exclusive-or
subsetp
union, nunion
subsetp almost does what you want, but it's checking for non-proper subsets. However, observe that you can use these functions to compute what you need. The most direct way would be to check if A is a subset of B, and whether B - A ≠ {}. This matches your description, "every element of a is found in b and b has another element".
(defun proper-subsetp (a b)
(and (subsetp a b) ; every element of a is found in b
(not (endp (set-difference b a))))) ; b has another element
CL-USER> (proper-subsetp '(1 2 3) '(1 2 3 4))
T
CL-USER> (proper-subsetp '(1 2 3 4) '(1 2 3 4))
NIL
Since these functions actually take some parameters that let you determine how elements are compared. You can add these in by using an &rest argument and apply:
(defun proper-subsetp (a b &rest keys)
(and (apply 'subsetp a b keys )
(not (endp (apply 'set-difference b a keys)))))
Using this, you could, rather than comparing the elements directly, compare their lengths:
CL-USER> (proper-subsetp '("a" "bb" "ccc") '("1" "22" "333") :key 'length)
NIL
CL-USER> (proper-subsetp '("a" "bb" "ccc") '("1" "22" "333" "4444") :key 'length)
T
The below only adds if to the set of operations you mention, but this is really an atrocious way to do it. If that's what they teach you (you didn't volunteer for it). It's about time you get some good book on Lisp and study it yourself. This exercise is really pointless in my opinion.
(defun purge (element from-list)
(if (null from-list) nil
(if (equal element (car from-list))
(purge element (cdr from-list))
(cons (car from-list) (purge element (cdr from-list))))))
(defun proper-subset-p (suspect of)
(if (null suspect) (not (null of))
(if (not (equal (purge (car suspect) of) of))
(proper-subset-p
(purge (car suspect) suspect)
(purge (car suspect) of)) nil)))
Same thing, but with cond
(defun purge (element from-list)
(cond
((null from-list) nil)
((equal element (car from-list)) (purge element (cdr from-list)))
(t (cons (car from-list) (purge element (cdr from-list))))))
(defun proper-subset-p (suspect of)
(cond
((null suspect) (not (null of)))
((not (equal (purge (car suspect) of) of))
(proper-subset-p (purge (car suspect) suspect) (purge (car suspect) of)))
(t nil)))