0
votes

I am working on a recursive function that takes a list and a value ex: 'b '(a. b), and returns nil if not found and t if found. my issue is in the line (cond ((eq A (car L)) t), it seems to be checking that condition even after (cond ((and (atom L (eq A L)) t) returns. I am under the impression that if that condition is met, execution stop and the function returns. Any way to fix this? Also, im only able to use primitive functions defun cond cons car cdr operators +, -, <, and > null eq listp atom symbolp

;test cases 
(checkInner 'b '(a . b))
(checkInner 'f '(c e f))
(checkInner 'b '(b))

;function 
(defun checkInner(A L)
    (cond ((and (atom L) (eq A L)) t)
    )
    (cond ((or (atom L) (eq A L)) nil)
    )
    (cond ((eq A (car L)) t)
            (t (checkInner A (cdr L))
            )
    )
)
3
Only the value of the last cond is returned by the function. - Barmar

3 Answers

3
votes

Unless you use an explicit (return-from checkInner value) expression, a function returns the value of its last expression. So the only value that's returned by your function is the last cond expression; the first two tests are ignored.

You need to combine all the cases into a single COND expression.

Also, the second test should not use or. If L is an atom, it won't be equal to L because we tested that in the previous case.

(defun checkInner(A L)
    (cond ((and (atom L) (eq A L)) t)
          ((atom L) nil)
          ((eq A (car L)) t)
          (t (checkInner A (cdr L)))))
0
votes

so I fixed it, thanks for confirming Barmer, this is my solution

(defun checkInner(A L)
    (cond ((and (atom L) (eq A L)) t)
        (t  (cond ((or (atom L) (eq A L)) nil)
                (t (cond ((eq A (car L)) t)
                        (t (checkInner A (cdr L))
                        )
                    )
                )
            )
        )
    )
)
0
votes

@Barmar You are basicaly checking the L being an atom twice, the first time could be written just as ((atom L) (eq A L)) (eq A L) is returning a boolean, so you don't need to explicitely return T from that clause, which overall contradicts with your second clause ((atom L) nil). Also note that this solution will not work on nested lists of elements (which would be the only argument willing to write your own recursive function and not just using the Lisp functions for testing memberships like member, find etc.)

(checkInner 'b '(a (c (d (b))))) ; => NIL

Following is a recursive definition that works on nested lists as well. Note that you can also supply an equality testing function for allowing your X being of different types.

(defun check-inner (x coll &key (test #'eq))
   "Check if X is in the collection. Works on nested lists 
and uses the test keyword argument for equality checking."
   (cond
    ((null coll) nil)
    ((listp (car coll)) (or (check-inner x (car coll) :test test)
                            (check-inner x (cdr coll) :test test)))
    ((atom (car coll)) (or (funcall test x (car coll))
                           (check-inner x (cdr coll) :test test)))
    (t (check-inner x (cdr coll :test test)))))

Now the thing you are looking for can be also hidden in nested layers in your list:

(check-inner 'b '(a (c (d (b))))) ; => T

Checking for other types is also no problem:

(check-inner "b" '(a (c (d ("b")))) :test #'string=) ; => T