Need to understand a LISP program with recursion - lisp

(defun help(a x)
(if (null x) nil
(cons (cons a (car x)) (help a (cdr x)))))
(defun partition(x)
(if (null x) '(nil)
(append (help (car x) (partition(cdr x))) (partition(cdr x)))))
This works like this: (partition '(a b)) -> ((A B) (A) (B) NIL)
I'm trying to understand how it works. Can someone illustrate what's going on to get the result? I tried following the code and writing down on paper but i failed.

The trace function allows you to visualize function calls in the LISP REPL.
Example output from sbcl
* (defun help(a x)
(if (null x) nil
(cons (cons a (car x)) (help a (cdr x)))))
HELP
* (defun partition(x)
(if (null x) '(nil)
(append (help (car x) (partition(cdr x))) (partition(cdr x)))))
PARTITION
* (trace help)
(HELP)
* (trace partition)
(PARTITION)
* (partition '(a b))
0: (PARTITION (A B))
1: (PARTITION (B))
2: (PARTITION NIL)
2: PARTITION returned (NIL)
2: (HELP B (NIL))
3: (HELP B NIL)
3: HELP returned NIL
2: HELP returned ((B))
2: (PARTITION NIL)
2: PARTITION returned (NIL)
1: PARTITION returned ((B) NIL)
1: (HELP A ((B) NIL))
2: (HELP A (NIL))
3: (HELP A NIL)
3: HELP returned NIL
2: HELP returned ((A))
1: HELP returned ((A B) (A))
1: (PARTITION (B))
2: (PARTITION NIL)
2: PARTITION returned (NIL)
2: (HELP B (NIL))
3: (HELP B NIL)
3: HELP returned NIL
2: HELP returned ((B))
2: (PARTITION NIL)
2: PARTITION returned (NIL)
1: PARTITION returned ((B) NIL)
0: PARTITION returned ((A B) (A) (B) NIL)
((A B) (A) (B) NIL)
Out side of that I'm not entirely sure how to be of more help.

Related

Common LISP: Make Your Own Union Function

I'm trying to make my own union function and realizing how much I dislike LISP. The goal is to give the function two lists and it will return a set theoretic union of the two. My attempted solution has grown increasingly complex with the same result: NIL. I can't change that from being the result no matter what I do.
I was thinking of building a separate list in my "removeDuplicates" function below, but then idk how I'd return that with recursion. I think what's happening is my "removeDuplicates" function eventually returns an empty list (as intended) but then an empty list is return at every level of the stack when the recursion unfurls (starts returning values up the stack) but I could be wrong. I've always had trouble understanding recursion in detail. The code is below.
(defun rember (A LAT)
(cond
((null LAT) ())
((EQ (car LAT) A) (cdr LAT))
(T (cons (car LAT)(rember A (cdr LAT))))
)
)
(defun my_member (A LAT)
(cond
((null LAT) nil)
((EQ (car LAT) A) T)
(T (my_member A (cdr LAT)))
)
)
(defun removeDuplicates (L)
(cond
((null L) '())
((my_member (car L) (cdr L)) (rember (car L) L) (removeDuplicates (cdr L)))
(T (removeDuplicates (cdr L)))
)
)
(defun my_union (A B)
(setq together(append A B))
(removeDuplicates together)
)
I'm aware most people are not a fan of this format of LISP code, but I prefer it. It allows me to see how parentheses line up better than if you just put all the closing parentheses together at the end of functions and condition blocks.
If I run (my_union '(a b) '(b c)) for example, the result is NIL.
When you call removeDuplicates recursively in the last condition, you're not combining the result with the car of the list, so you're discarding that element.
You're also not using the result of rember.
(defun removeDuplicates (L)
(cond
((null L) '())
((my_member (car L) (cdr L))
(cons (car L)
(removeDuplicates
(rember (car L) (cdr L))
))
)
(T (cons (car L) (removeDuplicates (cdr L))))
)
)
Here's a simple, obvious, union function:
(defun union/tfb (&rest lists)
;; compute the union of any number of lists, implicitly using EQL
(labels ((union/spread (l1 ls)
;; UNION/SPREAD just exists to avoid the impedance
;; mismatch in argument convention
(if (null ls)
l1
(let ((result l1))
(destructuring-bind (l2 . more) ls
(dolist (e l2 (union/spread result more))
(pushnew e result)))))))
(union/spread (first lists) (rest lists))))
I think this is reasonably natural CL, although of course the whole point of using a language like CL is avoiding endless wheel-reinvention like this.
So the rules of the game perhaps say you're not allowed to use PUSHNEW: well, you can easily can replace it with a conditional involving MEMBER:
(defun union/tfb (&rest lists)
;; compute the union of any number of lists, implicitly using EQL
(labels ((union/spread (l1 ls)
;; UNION/SPREAD just exists to avoid the impedance
;; mismatch in argument convention
(if (null ls)
l1
(let ((result l1))
(destructuring-bind (l2 . more) ls
(dolist (e l2 (union/spread result more))
;; Really use PUSHNEW for this
(unless (member e result)
(setf result (cons e result)))))))))
(union/spread (first lists) (rest lists))))
And perhaps you are also not allowed to use MEMBER: well you can easily write a predicate which does what you need:
(defun union/tfb (&rest lists)
;; compute the union of any number of lists, implicitly using EQL
(labels ((union/spread (l1 ls)
;; UNION/SPREAD just exists to avoid the impedance
;; mismatch in argument convention
(if (null ls)
l1
(let ((result l1))
(destructuring-bind (l2 . more) ls
(dolist (e l2 (union/spread result more))
;; Really use MEMBER for this, and in fact
;; PUSHNEW
(unless (found-in-p e result)
(setf result (cons e result))))))))
(found-in-p (e list)
;; is e found in LIST? This exists only because we're not
;; meant to use MEMBER
(cond ((null list) nil)
((eql e (first list)) t)
(t (found-in-p e (rest list))))))
(union/spread (first lists) (rest lists))))
If you want the result to be a set with unique elements even if the first list is not you can trivially do that (note CL's UNION does not promise this, and you can get the same result with the earlier version of UNION/TFB by (union/tfb '() ...)):
(defun union/tfb (&rest lists)
;; compute the union of any number of lists, implicitly using EQL
(labels ((union/spread (l1 ls)
;; UNION/SPREAD just exists to avoid the impedance
;; mismatch in argument convention
(if (null ls)
l1
(let ((result l1))
(destructuring-bind (l2 . more) ls
(dolist (e l2 (union/spread result more))
;; Really use MEMBER for this, and in fact
;; PUSHNEW
(unless (found-in-p e result)
(setf result (cons e result))))))))
(found-in-p (e list)
;; is e found in LIST? This exists only because we're not
;; meant to use MEMBER
(cond ((null list) nil)
((eql e (first list)) t)
(t (found-in-p e (rest list))))))
(union/spread '() lists)))
Finally if the rules prevent you using iterative constructs and assignment you can do that too:
(defun union/tfb (&rest lists)
;; compute the union of any number of lists, implicitly using EQL
(labels ((union/spread (l1 ls)
;; UNION/SPREAD just exists to avoid the impedance
;; mismatch in argument convention
(if (null ls)
l1
(union/loop l1 (first ls) (rest ls))))
(union/loop (result l more)
;; UNION/LOOP is just an iteration
(if (null l)
(union/spread result more)
(destructuring-bind (e . remainder) l
(union/loop (if (found-in-p e result)
result
(cons e result))
remainder more))))
(found-in-p (e list)
;; is e found in LIST? This exists only because we're not
;; meant to use MEMBER
(cond ((null list) nil)
((eql e (first list)) t)
(t (found-in-p e (rest list))))))
(union/spread '() lists)))
The final result of all these changes is something which is, perhaps, very pure, but is not natural CL at all: something like it might be more natural in Scheme (albeit not gratuitously replacing MEMBER with a home-grown predicate like this).
One way to test your Common Lisp code is to ask your interpreter to TRACE functions:
(trace removeDuplicates my_member rember)
To avoid having too many traces, use small examples.
First, let's try with an empty list; this is an example from the REPL ("read eval print loop"), tested with SBCL, while in the "SO" package (StackOverflow); the trace is printed a bit indented, a is numbered according to the depth of the recursion. Here the call is not recursive and terminates right away:
SO> (removeduplicates nil)
0: (SO::REMOVEDUPLICATES NIL)
0: REMOVEDUPLICATES returned NIL
NIL
This works, let's try an example with a singleton list, where there is obviously no duplicate:
SO> (removeduplicates '(1))
0: (SO::REMOVEDUPLICATES (1))
1: (SO::MY_MEMBER 1 NIL)
1: MY_MEMBER returned NIL
1: (SO::REMOVEDUPLICATES NIL)
1: REMOVEDUPLICATES returned NIL
0: REMOVEDUPLICATES returned NIL
NIL
removeDuplicate calls my_member, which correctly returns nil, followed by a recursive call to removeDuplicates with nil, which correctly returns nil. There is however a problem because then, the outermost call returns nil too, which is incorrect.
Looking at the trace, we have to look back at the code to find a place where my_member is called, followed by a recursive call to removeDuplicates. There is only one place wher my_member is called, as a test to the second clause in the cond;
Since the result is nil for that test, the next clause is tried, in that case the default case:
(cond
...
;; this is the call to my_member (= nil)
((my_member (car L) (cdr L)) ...)
;; this is the recursive call
(t (removeDuplicates (cdr L))))
The value of the cond is the one given by the last (removeDuplicates (cdr L)), which just does not retain the existing elements in front of L. If you were mutating a sequence, you could just recurse down the subsequence and ignore the previous elements: in that case the caller would still hold a reference to the original sequence, which would get its element removed by a side-effect of your functions. But here you are following a strictly immutable approach, and you have to recontruct a list as a return value.
In other words, removeDuplicates is expressed as: return a new list which contains the same elements as the original list, but without duplicates.
So you have to add (car L) in front of (removeDuplicates (cdr L)).
(defun removeDuplicates (L)
(cond
((null L) '())
((my_member (car L) (cdr L)) (rember (car L) L) (removeDuplicates (cdr L)))
(T (cons (car L)
(removeDuplicates (rest L))))))
Let's test:
SO> (removeduplicates '())
0: (SO::REMOVEDUPLICATES NIL)
0: REMOVEDUPLICATES returned NIL
NIL
SO> (removeduplicates '(1))
0: (SO::REMOVEDUPLICATES (1))
1: (SO::MY_MEMBER 1 NIL)
1: MY_MEMBER returned NIL
1: (SO::REMOVEDUPLICATES NIL)
1: REMOVEDUPLICATES returned NIL
0: REMOVEDUPLICATES returned (1)
(1)
You can test with a longer list (without duplicates), the result is correct, but the trace is longer.
Now, let's add duplicates:
SO> (removeduplicates '(1 2 2 1))
0: (SO::REMOVEDUPLICATES (1 2 2 1))
1: (SO::MY_MEMBER 1 (2 2 1))
2: (SO::MY_MEMBER 1 (2 1))
3: (SO::MY_MEMBER 1 (1))
3: MY_MEMBER returned T
2: MY_MEMBER returned T
1: MY_MEMBER returned T
1: (SO::REMBER 1 (1 2 2 1))
1: REMBER returned (2 2 1)
1: (SO::REMOVEDUPLICATES (2 2 1))
2: (SO::MY_MEMBER 2 (2 1))
2: MY_MEMBER returned T
2: (SO::REMBER 2 (2 2 1))
2: REMBER returned (2 1)
2: (SO::REMOVEDUPLICATES (2 1))
3: (SO::MY_MEMBER 2 (1))
4: (SO::MY_MEMBER 2 NIL)
4: MY_MEMBER returned NIL
3: MY_MEMBER returned NIL
3: (SO::REMOVEDUPLICATES (1))
4: (SO::MY_MEMBER 1 NIL)
4: MY_MEMBER returned NIL
4: (SO::REMOVEDUPLICATES NIL)
4: REMOVEDUPLICATES returned NIL
3: REMOVEDUPLICATES returned (1)
2: REMOVEDUPLICATES returned (2 1)
1: REMOVEDUPLICATES returned (2 1)
0: REMOVEDUPLICATES returned (2 1)
(2 1)
The result is correct (order does not matter).
So far, our tests are good.
You might not have identified the other problem in that function, namely that all calls to rember are useless, and frankly this is not necessarily easy to spot with the trace. But looking at the code, it should be clear if you write code to have little side-effects that the following clause calls (rember ...) for nothing:
((my_member (car L) (cdr L)) (rember (car L) L) (removeDuplicates (cdr L)))
A cond clause has for syntax (TEST . BODY), where BODY is a sequence of expressions that evaluates like a PROGN: the value of a PROGN is the value of its last clause, all intermediate clauses are only used for their side-effects. For example:
(progn
(print "I am here")
(* 10 3))
Here above, the call to PRINT returns a value, but it is discarded: the value of the enclosing PROGN is 30.
In your code, rember does no side-effect, and its return value is discarded. Just remove it:
(defun removeDuplicates (L)
(cond
((null L) '())
((my_member (car L) (cdr L))
(removeDuplicates (cdr L)))
(T (cons (first L)
(removeDuplicates (rest L))))))
I would write the same code as follows, personally:
(defun remove-duplicate-elements (list)
(when list
(let ((head (first list))
(tail (remove-duplicate-elements (rest list))))
(if (member head tail) tail (cons head tail)))))
Here is a remove-dupes that removes duplicates from a list in O(n) time using a hash table. It supports a custom equality function (which must be eq, eql, equal or `equalp) and a custom test function, so that any aspect of an item can be treated as the key.
(defun remove-dupes (list &key (test #'eql) (key #'identity))
(let ((hash (make-hash-table :test test)))
(loop for item in list
for item-key = (funcall key item)
for seen = (gethash item-key hash)
unless seen collect item and
do (setf (gethash item-key hash) t))))
For instance, suppose we have the assoc list ((a . 1) (a . 2) (b . 3) (c . 4) (b . 4)). We'd like to remove duplicates by car:
[1]> (remove-dupes '((a . 1) (a . 2) (b . 3) (c . 4) (b . 4)) :key #'car)
((A . 1) (B . 3) (C . 4))
Only the leftmost A, B and C entries are reported; the duplicates are suppressed. Now let's do it by cdr:
[2]> (remove-dupes '((a . 1) (a . 2) (b . 3) (c . 4) (b . 4)) :key #'cdr)
((A . 1) (A . 2) (B . 3) (C . 4))
The (b . 4) got culled due to the duplicated 4 value.
But, why do all this, when Common Lisp provides a remove-duplicates function (not to mention union).
remove-duplicates is more general than what I have here: it handles sequences, rather than just lists, so it works on vectors and strings. It has more keyword parameters.

how to take care mutiply condition check in Common lisp?

Just learning Common Lisp for a few days, but Professor had assigned an exercise for me. However, my code is not able to compile, Can anyone show me where I did wrong with my coding part?
(defun( MIN-2 a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
Literal translation:
(defun min-2 (a b) ; Define a Lisp function MIN-2 … takes two arguments A and B
(cond ((and (every #'numberp (list a b)) (<= a b)) a) ; if … A <= B, returns A
((and (every #'numberp (list a b)) (> a b)) b) ; if … A > B, returns B
(t 'error) ; if A or B is not a number (i. e. “else”), returns ERROR
Improvement: check for numbers just once beforehand.
(defun min-2 (a b)
(cond ((not (every #'numberp (list a b))) 'error)
((<= a b) a)
((> a b) b)))
And please indent your code and don't leave the parentheses lying around.
Why your code fails
Can anyone show me where I did wrong with my coding part?
(defun( MIN-2 a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
Let me reformat your code (auto-indent + compress parentheses):
(defun (MIN-2 a b) ;; << bad syntax, as already pointed out in another answer
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b) nil)
ERROR)))
Let's fix the syntax of defun:
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b) nil)
ERROR)))
Error (I am compiling the code under Emacs + SBCL):
Undefined variable: ERROR
Indeed, error is a free variable here. You need to quote it.
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b))
a
b)
((and (numberp a) (numberp b))
'ERROR)))
Warning:
Deleting unreachable code (ERROR is underlined).
Indeed, the condition here is a and expression where at least one of the
expression is NIL, which means the conjunction is always false. The case can never happen, which is why the was optimized away.
Also, the first clause's test is:
(and (numberp a) (numberp b) (<= a b))
And the clause body is a followed by b, which means a is evaluated, its value discarded (it is never used), then b is evaluated and its value is the value of the cond expression: you always return b when both inputs are numbers such that a <= b.
Clearly, this is not what you should do. Other answers already covered good solutions.
Alternatives
I am also here to offer alternative, not necessarily homework-friendly answers:
Catch exceptions
(defun min-2 (a b)
(handler-case (if (<= a b) a b)
(error () 'error)))
Catch exceptions (bis)
(defun min-2 (a b)
(or (ignore-errors (if (<= a b) a b))
'error))
Use generic functions
(defgeneric min-2 (a b)
(:method ((a number) (b number)) (if (<= a b) a b))
(:method (a b) 'error))
You are using the wrong syntax for defining a function. Use defun function-name (args)
(defun MIN-2 (a b)
(cond
((and (numberp a) (numberp b) (<= a b)) a b)
((and (numberp a) (numberp b) nil) ERROR)
)
)
I think it's worth writing functions like this in a way which makes clear what is the sanity check and what is the actual computation. So in this case the sanity check is: 'are both arguments numbers?' and the computation is the comparison of them if they are. So separate these two things rather than bundling it all into one conditional:
(defun min-2 (a b)
(if (and (numberp a) (numberp b))
;; sanity check OK, so compare them
(if (<= a b)
a
b)
'error))
Unfortunately, of course, the sanity check is not adequate:
> (min-2 1 2)
1
> (min-2 1 'a)
error
> (min-2 1 #c(1 1))
Error: In <= of (1 #C(1 1)) arguments should be of type real.
Oops: what the sanity check should be is whether the two arguments are real numbers. Fortunately, there's a predicate for that, which is realp. So a correct version of min-2 is:
(defun min-2 (a b)
(if (and (realp a) (realp b))
;; sanity check OK, so compare them
(if (<= a b)
a
b)
'error))

Edit every even-indexed element in a list

I'm pretty new to lisp and I want to make function that every even-indexed element replace it with new one element list that holds this element. For example
(1 2 3 4 5) -> (1 (2) 3 (4) 5), (1 2 3 4 5 6) -> (1 (2) 3 (4) 5 (6))
Right now I came up with solution that each of the lements put in it's own list, but I cant get exactly how to select every even-indexed element:
(DEFUN ON3 (lst)
((ATOM (CDR lst)) (CONS (CONS (CAR lst) NIL) NIL))
(CONS (CONS (CAR lst) NIL) (ON3 (CDR lst))))
Your code doesn't work. You'll need to use if or cond such that the code follow one of the paths in it. Right now you have an error truing to call a function called (atom (cdr lst)). If it had been something that worked it would be dead code because the next line is always run regardless. It is infinite recursion.
So how to count. You can treat every step as a handle on 2 elements at a time. You need to take care of the following:
(enc-odds '()) ; ==> ()
(enc-odds '(1)) ; ==> (1)
(enc-odds '(1 2 3 ...) ; ==> (1 (2) (enc-odds (3 ...))
Another way is to make a helper with extra arguments:
(defun index-elements (lst)
(labels ((helper (lst n)
(if (null lst)
lst
(cons (list (car lst) n)
(helper (cdr lst) (1+ n))))))
(helper lst 0)))
(index-elements '(a b c d))
; ==> ((a 0) (b 1) (c 2) (d 3))
For a non-recursive solution, loop allows for constructing simultaneous iterators:
(defun every-second (list)
(loop
for a in list
for i upfrom 1
if (evenp i) collect (list a)
else collect a))
(every-second '(a b c d e))
; ==> (A (B) C (D) E)
See http://www.gigamonkeys.com/book/loop-for-black-belts.html for a nice explanation of loop

List without nil in result Lisp

I have to delete all occurences of an element in a list from all levels.
My code is:
(defun sterge(e l)
(cond
((and (atom l) (equal e l)) nil)
((atom l) (list l))
(t (append (apply #'list (mapcar #' (lambda (l) (sterge e l)) l))))
)
)
(defun sterg(e l)
(car (sterge e l))
)
When I give:
(sterg 1 '(1 2 1 ( 1 2 1( 1 (1) (1)) (1) 3) (1)(2)))
it shows me the output:
((2 (2 (NIL NIL) NIL 3) NIL (2)))
How to delete that nil?? Thank you.
Instead of returning nil, consider returning sterge applied to the rest of the entity l. mapcar is not the best way to approach this problem; a recursive function is better (unless the assignment specifies using mapcar, of course.)
Hint: Treat l as if it were a list and test (car l), e.g., (atom (car l)), apply sterge to (cdr l).

Why does this Lisp function keep giving me a stack overflow?

This function here:
(defun test (a)
(if (equal a nil) 0)
(if (listp (car a)) (print "a")
(print "b"))
(test (cdr a))
)
I want it to return 0 if a is nil which is the base case. then if the element in the front of the list is a list, print the letter a otherwise print b then call function again. Why doesn't the base case prevent the infinite loop?
Your code ends up with a stack overflow because you recurse into test regardless of the result of the nil-check.
(defun test (a)
(if (equal a nil) 0) ; <-- problem is partly here...
(if (listp (car a))
(print "a")
(print "b"))
(test (cdr a))) ; <-- ...and partly down here
Even if (equal a nil) evaluates to T and the surrounding if therefore evaluates to 0, you basically ignore this result, because the next step you do is checking if a is a list regardless of the outcome of the previous nil-check. Eventually you call test again without taking the result of your comparisons into consideration.
Keep in mind that the result of a function in Lisp is the result of the last evaluated expression, meaning that if you want your function to return 0 you have to make 0 the last evaluated expression.
The following code behaves as you specified:
(defun test (a)
(if (null a)
0
(progn
(if (listp (car a))
(print "a")
(print "b"))
(test (cdr a)))))
Note that you can use null to do a nil-check.
If a is not nil, then and only then, a is examined further. For this purpose progn lets you evaluate a sequence of expressions and eventually evaluates to the result of its last expression.
The other answers have explained your problem very well; just 2 notes:
cond
At least one style guide advises againt the use of if and prefers cond; this would have avoided the "fall-through problem":
(defun test (a)
(cond
((equal a nil) 0)
(t (if (listp (car a))
(print "a")
(print "b"))
(test (cdr a)))))
return
You can return early from a function; your code would have worked with a return-from clause:
(defun test (a)
(if (equal a nil) (return-from test 0))
(if (listp (car a))
(print "a")
(print "b"))
(test (cdr a)))
Because your base case is still followed by the printing and recursion. It didn't return straight afterwards.
Perhaps you wanted this:
(defun test (a)
(if (null a)
0
(progn (if (listp (car a))
(print "a")
(print "b"))
(test (cdr a)))))