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.
Related
I want to implement the sorting function in common-lisp with this INSERT function
k means cons cell with number & val, and li means list where I want insert k into.
with this function, I can make a list of cell
(defun INSERT (li k) (IF (eq li nil) (cons (cons(car k)(cdr k)) nil)
(IF (eq (cdr li) nil)
(IF (< (car k)(caar li)) (cons (cons(car k)(cdr k)) li)
(cons (car li) (cons (cons(car k)(cdr k)) (cdr li)) )
)
(cond
( (eq (< (caar li) (car k)) (< (car k) (caadr li)) )
(cons (car k) (cons (cons (car k) (cdr k)) (cdr li)) ) )
(t (cons (car li) (INSERT (cdr li) k)) )))))
and what I want is the code of this function below. it has only one parameter li(non sorted list)
(defun Sort_List (li)(...this part...))
without using assignment, and using the INSERT function
Your insert function is very strange. In fact I find it so hard to read that I cn't work out what it's doing except that there's no need to check for both the list being null and its cdr being null. It also conses a lot of things it doesn't need, unless you are required by some part of the specification of the problem to make copies of the conses you are inserting.
Here is a version of it which is much easier to read and which does not copy when it does not need to. Note that this takes its arguments in the other order to yours:
(defun insert (thing into)
(cond ((null into)
(list thing))
((< (car thing) (car (first into)))
(cons thing into))
(t (cons (first into)
(insert thing (rest into))))))
Now, what is the algorithm for insertion sort? Well, essentially it is:
loop over the list to be sorted:
for each element, insert it into the sorted list;
finally return the sorted list.
And we're not allowed to use assignment to do this.
Well, there is a standard trick to do this sort of thing, which is to use a tail-recursive function with an accumulator argument, which accumulates the results. We can either write this function as an explicit auxiliary function, or we can make it a local function. I'm going to do the latter both because there's no reason for a function which is only ever used locally to be globally visible, and because (as I'm assuming this is homework) it makes it harder to submit directly.
So here is this version of the function:
(defun insertion-sort (l)
(labels ((is-loop (tail sorted)
(if (null tail)
sorted
(is-loop (rest tail) (insert (first tail) sorted)))))
(is-loop l '())))
This approach is fairly natural in Scheme, but not very natural in CL. An alternative approach which does not use assignment, at least explicitly, is to use do. Here is a version which uses do:
(defun insertion-sort (l)
(do ((tail l (rest tail))
(sorted '() (insert (first tail) sorted)))
((null tail) sorted)))
There are two notes about this version.
First of all, although it's not explicitly using assignment it pretty clearly implicitly is doing so. I think that's probably cheating.
Secondly it's a bit subtle why it works: what, exactly, is the value of tail in (insert (first tail) sorted), and why?
A version which is clearer, but uses loop which you are probably not meant to know about, is
(defun insertion-sort (l)
(loop for e in l
for sorted = (insert e '()) then (insert e sorted)
finally (return sorted)))
This, however, is also pretty explicitly using assignment.
As Kaz has pointed out below, there is an obvious way (which I should have seen!) of doing this using the CL reduce function. What reduce does, conceptually, is to successively collapse a sequence of elements by calling a function which takes two arguments. So, for instance
(reduce #'+ '(1 2 3 4))
is the same as
(+ (+ (+ 1 2) 3) 4)
This is easier to see if you use cons as the function:
> > (reduce #'cons '(1 2 3 4))
(((1 . 2) . 3) . 4)
> (cons (cons (cons 1 2) 3) 4)
(((1 . 2) . 3) . 4)
Well, of course, insert, as defined above, is really suitable for this: it takes an ordered list and inserts a new pair into it, returning a new ordered list. There are two problems:
my insert takes its arguments in the wrong order (this is possibly why the original one took the arguments in the other order!);
there needs to be a way of 'seeding' the initial sorted list, which will be ().
Well we can fix the wrong-argument-order either by rewriting insert, or just by wrapping it in a function which swaps the arguments: I'll do the latter because I don't want to revisit what I wrote above and I don't want two versions of the function.
You can 'seed' the initial null value by either just prepending it to the list of things to sort, or in fact reduce has a special option to provide the initial value, so we'll use that.
So using reduce we get this version of insertion-sort:
(defun insertion-sort (l)
(reduce (lambda (a e)
(insert e a))
l :initial-value '()))
And we can test this:
> (insertion-sort '((1 . a) (-100 . 2) (64.2 . "x") (-2 . y)))
((-100 . 2) (-2 . y) (1 . a) (64.2 . "x"))
and it works fine.
So the final question the is: are we yet again cheating by using some function whose definition obviously must involve assignment? Well, no, we're not, because you can quite easily write a simplified reduce and see that it does not need to use assignment. This version is much simpler than CL's reduce, and in particular it explicitly requires the initial-value argument:
(defun reduce/simple (f list accum)
(if (null list)
accum
(reduce/simple f (rest list) (funcall f accum (first list)))))
(Again, this is not very natural CL code since it relies on tail-call elimination to handle large lists, but it makes the point that you can do this without assignment.)
And so now we can write one final version of insertion-sort:
(defun insertion-sort (l)
(reduce/simple (lambda (a e)
(insert e a))
l '()))
And it's easy to check that this works as well.
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 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.
I'm trying to implement the Towers of Hanoi.I'm not printing out anything between my recursive calls yet, but I keep getting an error saying
'('(LIST) 'NIL 'NIL) should be a lambda expression
I've read that the reason this happens is because of a problem with the parenthesis, however I cannot seem to find what my problem is. I think it's happening in the pass-list function when I am trying to call the hanoi function. My code:
(defun pass-list(list)
(hanoi('('(list)'()'())))
)
(defun hanoi ('('(1) '(2) '(3)))
(hanoi '('(cdr 1) '(cons(car 1) 2) '(3)))
(hanoi '('(cons(car 3)1) '(2)'(cdr 3)))
)
This code has many syntax problems; there are erroneous quotes all over the place, and it looks like you're trying to use numbers as variables, which will not work. The source of the particular error message that you mentioned comes from
(hanoi('('(list)'()'())))
First, understand that the quotes in 'x and '(a b c) are shorthand for the forms (quote x) and (quote (a b c)), and that (quote anything) is the syntax for getting anything, without anything being evaluated. So '(1 2 3) gives you the list (1 2 3), and '1 gives you 1. quote is just a symbol though, and can be present in other lists, so '('(list)'()'()) is the same as (quote ((quote (list)) (quote ()) (quote ()))) which evaluates to the list ((quote (list)) (quote ()) (quote ())). Since () can also be written nil (or NIL), this last is the same as ('(list) 'NIL 'NIL). In Common Lisp, function calls look like
(function arg1 arg2 ...)
where each argi is a form, and function is either a symbol (e.g., list, hanoi, car) or a list, in which case it must be a lambda expression, e.g., (lambda (x) (+ x x)). So, in your line
(hanoi('('(list)'()'())))
we have a function call. function is hanoi, and arg1 is ('('(list)'()'())). But how will this arg1 be evaluated? Well, it's a list, which means it's a function application. What's the function part? It's
'('(list)'()'())
which is the same as
'('(list 'NIL 'NIL))
But as I just said, the only kind of list that can be function is a lambda expression. This clearly isn't a lambda expression, so you get the error that you're seeing.
I can't be sure, but it looks like you were aiming for something like the following. The line marked with ** is sort of problematic, because you're calling hanoi with some arguments, and when it returns (if it ever returns; it seems to me like you'd recurse forever in this case), you don't do anything with the result. It's ignored, and then you go onto the third line.
(defun pass-list(list)
(hanoi (list list) '() '()))
(defun hanoi (a b c)
(hanoi (rest a) (cons (first a) b) c) ; **
(hanoi (cons (first c) a) b (rest c)))
If hanoi is supposed to take a single list as an argument, and that list is supposed to contain three lists (I'm not sure why you'd do it that way instead of having hanoi take just three arguments, but that's a different question, I suppose), it's easy enough to modify; just take an argument abc and extract the first, second, and third lists from it, and pass a single list to hanoi on the recursive call:
(defun hanoi (abc)
(let ((a (first abc))
(b (second abc))
(c (third abc)))
(hanoi (list (rest a) (cons (first a) b) c))
(hanoi (list (cons (first c) a) b (rest c)))))
I'd actually probably use destructuring-bind here to simplify getting a, b, and c out of abc:
(defun hanoi (abc)
(destructuring-bind (a b c) abc
(hanoi (list (rest a) (cons (first a) b) c))
(hanoi (list (cons (first c) a) b (rest c)))))
I have to build a function which determines if I have a conjunction of well-formed formulas built in this way :
cong ::= '(' and wff wff ...')'
Let's suppose I have the code which determines if a formula is wff. The function must first check if the first element of the list is 'and and then check recursively the rest of the sublists if they are wff. Note that p is also a wff so it doesn't neccessarily have to be a sublist.
Example : (and (or a b v) (and a b d) m n)
Here's what I tried which doesn't work for me :
(defun cong (fbf)
(and (eq (first fbf) 'and )
(reduce (lambda (x y) (and x y))
(mapcar #'wff (rest fbf)))))
Assuming a working wff predicate, your code will work. For example, using numberp as the predicate:
(defun cong (fbf)
(and (eq (first fbf) 'and)
(reduce (lambda (x y) (and x y))
(mapcar #'numberp (rest fbf)))))
Works fine:
CL-USER> (cong '(and 1 2 3 4 5))
T
CL-USER> (cong '(and 1 2 3 4 foo))
NIL
CL-USER> (cong '(1 2 3 4))
NIL
Note, that this can be done more easily:
(defun cong (fbf)
(and (eq (first fbf) 'and)
(every #'wff (cdr fbf))))
Also, note that in CL, by convention, predicates usually should end in p.
So, your, given your comment above, your problem is the wff predicate, which doesn't seem to work for atoms. Since you mentioned that p satisfies wff, that predicate is plain wrong, but if you have to use it (assuming this is some kind of homework), just check if the element at hand is a cons:
(defun cong (fbf)
(and (eq (first fbf) 'and)
(every #'wff (remove-if-not #'consp (cdr fbf)))))
This assumes that every atom satisfies wff. Thus, they won't change the outcome of a conjunction and can be dropped. Otherwise, you'd have to write another predicate to check for atoms satisfying wff or, which would be the right thing to do, fix wff in the first place.
Also, note that none of this really involves recursion, since you're only asking how to apply a predicate to a list and take the conjunction of the results.