shrekkino sciocchino
shrekkino sciocchino

Reputation: 33

can anyone explain to me why this lisp code doesn't work?

it should count the elements of a list, but says "*** - +: NIL is not a number"

(setq A '(2 3 4 3 2 6 7 8 4 3 5 6))

(defun big (A) 
   (if (not (null (car A)))   (+ 1 (big (cdr A)))  )   ;if the first element is not null, add 1 to the count of the elements to the rest of the list
)     
 
(print (big A))

Upvotes: 3

Views: 144

Answers (2)

coredump
coredump

Reputation: 38967

Type error

An IF expression has either 2 or 3 arguments:

(if test something)

(if test something something-else)

When it only has 2 arguments, it is as-if the third argument, something-else, was NIL. That means that the IF expression evaluates to NIL when the test expression is false. In your case, you have 2 arguments:

(defun big (A) 
  (if (not (null (car A)))
      ;; "then" branch (when condition is true)
      (+ 1 (big (cdr A)))
      ;; no "else" branch (when condition is false)
      ))

So you know that sometimes a call to big might return NIL.

But, you also write:

(+ 1 (big (cdr A)))

This expression looks like (+ 1 x) with x being a call to big, meaning that x might evaluate to NIL in some cases. That's the case you hit with the debugger.

If you make sure the if expression always return a number, by returning for example zero in the else branch, then you won't have the same error about trying to add a number to NIL.

Counting elements

But then, you would still have other bugs, since you say that the function big "should count the elements of a list". If you want to count the element of a list, you never need to look at the elements stored in the list, you only need to know that they exist.

When you write (car a), you are accessing the first element of the list. You then check if that value is non-nil, but it is perfectly valid to have a list filled with NIL values:

'(NIL NIL NIL)

That list has 3 elements, and at no point the fact that they are NIL should matter when counting them.

A recursive function working on a list typically needs to cover two cases, namely if the list is empty or not. You check if the current list is empty by calling (null list) or (endp list) (just doing (if list ... ...) works too since NIL is the only false value).

Upvotes: 3

Nathan Hughes
Nathan Hughes

Reputation: 96454

The test for null car doesn’t do any good, cdr will return nil before car does.

You need a base case where you find you’re done and return something instead of recursing. Right now you don’t have that. Look at examples of simple recursive functions and see how they have a base case.

To count the elements in a list there are two cases:

The base case where the list is empty (return 0)

The recursive case where the list isn’t empty (return 1 + the count of the cdr of the passed in list)

Upvotes: 2

Related Questions