I'm just starting to learn Common Lisp and the text I'm reading uses an example with the member function.
I'm unsure of the distinction between these two blocks of code:
(if (member nil '(1 nil 2 3))
'contains-nil
'does-not-contain-nil)
returns CONTAINS_NIL
(if (member nil '(1 2 3))
'contains-nil
'does-not-contain-nil)
returns DOES-NOT-CONTAIN-NIL
From what I understand, lists are equivalent to nested cons cells, so I would think (member nil (cons 1 (cons 2 (cons 3 nil))) would return (nil), but it just returns nil. I'm not sure how a compiler or interpreter would make that distinction, and if someone could give me some insight on how I could implement the member function, I'd appreciate it.
A cons cell holds two values, typically called its car and its cdr. The expression (cons x y) returns a cons cell whose car is x, and whose cdr is y. In Lisp, a list is either the empty list (typically the symbol nil), or a cons cell. When a list is a cons cell, the first element of the list is the cons cell's car, and the rest of the list is the cons cell's cdr. Consider the list (1 2 3). It is a cons cell, and the first element of the list is 1. The rest of the list is not empty, so it must be another list whose first element is 2. The rest of that list is not empty, so it must be another list whose first element is 3. The rest of that list is empty, i.e., nil. Based on that analysis, we can see why the list is formed by
(cons 1 (cons 2 (cons 3 nil)))
== (1 2 3)
In a chain of cons cells that make up a list, the elements of the list are the car values of each cons cell in the chain. Lists can be elements of lists, as in
(cons 1 (cons nil (cons 2 (cons 3 nil))))
== (1 nil 2 3)
or
(cons 1 (cons (cons 2 (cons 3 nil)) nil))
== (1 (2 3))
but just because we see nil in the longer expression doesn't mean that nil is an element of the list.
MEMBER looks only at the elements of the list, not the list itself. An empty list is something different than an empty list with another empty list as an element.
() is not the same as (()). () is not the same as (nil).
Since a list is made of cons cells, the elements are the cars of the cons cells.
A list is defined to be either the empty list NIL or to be a cons cell whose CAR is an element of the list and whose CDR is another list.
The list that is produced by
(cons 1 nil)
is a list that has the element 1 and also all the elements of the empty list. The empty list has no elements, so NIL is not an element of the list.
It is similar with sets: Although the empty set is a subset of any set it is not an element of every set (while it isn't generally prohibited from being an element of a set).
One way o implement MEMBER is like this:
(defun member (item list)
(if list
(if (eql item (car list))
list
(member item (cdr list)))))
So if LIST is NIL the whole function will return NIL.
Our own version of the predefined member function in lisp can be defined as :
(defun member2 (item lst)
(if lst
(if (eql item (car lst))
T
(member2 item (cdr lst)))))
Related
(equal? '(1 2) (cons 1 2)) ; #f
Why exactly are these two not equivalent considering lists are just that — illusion built on top of cons cells.
(cons 1 2) does not create a proper list. It creates a cons cell with two elements, both are numbers.
A normal list is recursively defined as:
the empty list
or a cons cell with an object as the car and a list as the cdr.
In your call 2 is not a list, but a number. The second argument to cons must be a list to get a proper list.
(1 2)
in (1 2), the car element is a number, the cdr element is (2).
in (2), the car element is a number, the cdr element is (), the empty list.
() is the empty list.
Thus (1 2) is a list according to the definition above.
(cons 1 2) creates (1 . 2), which is not a list according to the definition above, since 2 is not a list.
A list is a chain of conses, with one cons for each element. So '(1 2) is equivalent to (cons 1 (cons 2 '())), which can be simplified to (list 1 2).
The literal equivalent to (cons 1 2) is '(1 . 2)
The question is tagged "racket" and "lisp", here I'm using the Common Lisp language but apart from details this is the same in Racket.
The literal list as read by the Lisp reader when reading the following text:
'(1 2)
can be built by evaluating the following form:
(cons 1 (cons 2 nil))
This is different from:
(cons 1 2)
Which also can be read using a special syntax, as follows:
'(1 . 2)
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))
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).
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)
I am new to lisp and I have a problem, I'm trying to find the number in the list but it is not working. I haven't made the return statement yet
(defun num (x 'y)
(if (member x '(y)) 't nil))
(write (num 10 '(5 10 15 20)))
My output just outputs the nil instead of doing the function and I'm confused of what I am doing wrong.
Solution
(defun member-p (element list)
"Return T if the object is present in the list"
(not (null (member element list))))
The not/null pattern is equivalent to (if (member element list) t nil) but is more common.
In fact, you do not really need this separate function,
member is good enough.
The -p suffix stands for predicate, cf. integerp and upper-case-p.
Your code
You cannot quote lambda list elements, so you need to replace defun num (x 'y) with defun num (x y)
You need not quote t
Quoting '(y) makes no sense, replace it with y.
You do not need to write the function call, the REPL will do it for you.
See also
When to use ' (or quote) in Lisp?
Can you program without REPL on Lisp?
You are almost certainly expected to not just use member, but to write a function which does what you need (obviously in real life you would just use member because that's what it's for).
So. To know if an object is in a list:
if the list is empty it's not;
if the head of the list is equal to the object it is;
otherwise it is in the list if it's in the tail of the list.
And you turn this into a function very straightforwardly:
(defun num-in-list-p (n l)
;; is N in L: N is assumed to be a number, L a list of numbers
(cond ((null l)
nil)
((= n (first l))
t)
(t
(num-in-list-p n (rest l)))))
You could use the built in position function which will return the index of the number if it is in the list:
(position 1 '(5 4 3 2 1))
If you want to define your own function:
CL-USER> (defun our-member(obj lst)
(if(zerop (length lst))
nil
(if(equal(car lst)obj)
T
(our-member obj (cdr lst)))))
OUR-MEMBER
CL-USER> (our-member 1 '(5 4 3 2 1))
T
CL-USER> (our-member 99 '(1 2 3 4 5))
NIL
We can create a function called "our-member" that will take an object (in your case a number) and a list (in your case a list of numbers) as an argument. In this situation our "base-case" will be whether or not the length of the list is equal to zero. If it is and we still haven't found a match, we will return nil. Otherwise, we will check to see if the car of the list (the first element in the list) is equal to the obj that we passed. If so, we will return T (true). However, if it is not, we will call the function again passing the object and the cdr of the list (everything after the car of the list) to the function again, until there are no items left within the list. As you can see, The first example of a call to this function returns T, and the second example call returns NIL.
What makes this utility function a good example is that it essentially shows you the under workings of the member function as well and what is going on inside.
I don't understand the following paragraph:
(COUNT-ATOMS ’(A (B) C)) should return five.
A, B, and C and two NILs in the tree.
Write a function COUNT-ATOMS that returns the number of atoms in a tree.
I tried this:
(defun count-atoms(l)
(cond
((null l) 0)
(t (+ (cond
((atom (car l)) 1)
(t 0))
(count-atoms (cdr l))))))
However, (COUNT-ATOMS '(A (B) C)) return 2.
How should I do to return 5 instead?
Could you explain in more details?
If you wanted to build (a (b) c) at runtime, using only cons and quote, you would write:
(cons 'a
(cons (cons 'b nil)
(cons 'c nil)))
There are 5 atoms (a, b, c and two nil) in the tree being built. In practice you could use a simpler notation, like (list 'a (list 'b) 'c).
In your function, you do not recurse into the CARS of your trees, only the CDRS. Also, when the CAR is not an atom, like when you encounter (B), you add zero (the default clause in the second cond) (edit. As kmkaplan noted, you also count zero for nil, first cond).
A simple solution is this, based on typecase:
(defun count-atoms (form)
(typecase form
(atom 1)
(cons (+ (count-atoms (car form))
(count-atoms (cdr form))))))
When you encounter an atom, the result is 1.
When you have a cons cell, you sum the number of atoms in its car and cdr.
The typecase dispatches according to the type of its argument, here form. Each clause has the following syntax: (type ...body...), where type is the name of a type and ...body... one or more expressions (an implicit progn): the last value is the return value of the typecase, if the argument matches the type type.
The first clause (atom 1) says: if form is an atom, return 1. The following one, (cons ...) says: else, if form is a cons cell, .... Here, atom is the name of a type, which represents everything that is not a cons. Granted, once you know that something is not an atom, you know that it is necessarily a cons, and the second test is redundant. However, it is more readable and any decent compiler will optimize the second test away.
There is also a function named atom, which is a predicate that tests whether a value is an atom. That's why, when you write (atom 1) on its own, in the REPL, it returns T.
See also wikipedia and Seibel's Practical Common Lisp's chapter about lists.
Your function has two problems. The first, neatly described in coredump's answer, is that your COUNT-ATOMS only recurse on the tail (CDR) and forget to recurse on the CAR element of your cons cell (L). Thus it fails to count the B atom.
The second problem is that you count NIL as 0 while it is an atom and should be counted as 1.
I have to write a program in Lisp that returns the first item of a list if it contains an even number of elements, and the last if it contains an odd number of elements. I need a little advice on where to start? I don't need whole program.
You can get the length of a list with length.
(length '(a b c)) ;; 3
You can then go and check that number against the predicate function evenp, which returns T or NIL depending on if the argument is even or not.
(evenp 1) ;; NIL
(evenp 2) ;; T
The function first returns the first element of a list.
(first '(a b c)) ;; A
The function last returns the last cons of a list, so you'll have to unwrap the value using FIRST.
(last '(a b c)) ;; (C)
(first (last '(a b c))) ;; C
You could then combine these into a function like so:
(defun get-first-if-even-length (list)
(if (evenp (length list))
(first list)
(first (last list))))
This function returns the first or the last element in the list, depending if its length is even or not.