How does "Cons" work in Lisp? - lisp

I was studying Lisp and I am not experienced in Lisp programming. In a part of my studies I encountered the below examples:
> (cons ‘a ‘(a b)) ----> (A A B)
> (cons ‘(a b) ‘a) ----> ((A B).A)
I was wondering why when we have (cons ‘a ‘(a b)) the response is (A A B) and why when we change it a little and put the 'a after (a b), the response is a dotted list like ((A B).A)? What is the difference between the first code line and the second one? What is going on behind these codes?

It's pretty easy to understand if you think of them as cons-cells.
In short, a cons cell consists of exactly two values. The normal notation for this is to use the dot, e.g.:
(cons 'a 'b) ==> (A . B)
But since lists are used so often in LISP, a better notation is to drop the dot.
Lists are made by having the second element be a new cons cell, with the last ending a terminator (usually nil, or '() in Common Lisp). So these two are equal:
(cons 'a (cons 'b '())) ==> (A B)
(list 'a 'b) ==> (A B)
So (cons 'a 'b) creates a cell [a,b], and (list 'a 'b) will create [a, [b, nil]]. Notice the convention for encoding lists in cons cells: They terminate with an inner nil.
Now, if you cons 'a onto the last list, you create a new cons cell containing [[a, [b, nil]], a]. As this is not a "proper" list, i.e. it's not terminated with a nil, the way to write it out is to use the dot: (cons '(a b) 'a) ==> ((a b) . a).
If the dot wasn't printed, it would have to have been a list with the structure [[a, [b, nil]], [a, nil]].
Your example
When you do (cons 'a '(a b)) it will take the symbol 'a and the list '(a b) and put them in a new cons cell. So this will consist of [a, [a, [b, nil]]]. Since this naturally ends with an inner nil, it's written without dots.
As for (cons '(a b) 'a), now you'll get [[a, [b, nil]], a]. This does not terminate with an inner nil, and therefore the dot notation will be used.
Can we use cons to make the last example end with an inner nil? Yes, if we do
(cons '(a b) (cons 'a '())) ==> ((A B) A)
And, finally,
(list '(a b) 'a))
is equivalent to
(cons (cons (cons 'a (cons 'b '())) (cons 'a '())))

See this visualization:
CL-USER 7 > (sdraw:sdraw '(A A B))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
A A B
CL-USER 8 > (sdraw:sdraw '((A B) . A))
[*|*]--->A
|
v
[*|*]--->[*|*]--->NIL
| |
v v
A B
Also:
CL-USER 9 > (sdraw:sdraw '(A B))
[*|*]--->[*|*]--->NIL
| |
v v
A B
CL-USER 10 > (sdraw:sdraw (cons 'A '(A B)))
[*|*]--->[*|*]--->[*|*]--->NIL
| | |
v v v
A A B
CL-USER 11 > (sdraw:sdraw (cons '(A B) 'A))
[*|*]--->A
|
v
[*|*]--->[*|*]--->NIL
| |
v v
A B

A cons is a data structure that can contain two values. Eg (cons 1 2) ; ==> (1 . 2). The first part is car, the second is cdr. A cons is a list if it's cdr is either nil or a list. Thus
(1 . (2 . (3 . ()))) is a list.
When printing cons the dot is omitted when the cdr is a cons or nil. The outer parentheses of the cdr is also omitted. Thus (3 . ()) is printed (3) and (1 . (2 . (3 . ()))) is printed (1 2 3). It's the same structure, but with different visualization. A cons in the car does not have this rule.
The read function reads cons with dot and the strange exceptional print format when the cdr is a list. It will at read time behave as if it were cons.
With a special rule for both read and print the illusion of a list is complete even when it's chains of cons.
(cons ‘a ‘(a b)) ----> (A . (A B))
(cons ‘(a b) ‘a) ----> ((A B) . A)
When printing, the first is one list of 3 elements since the cdr is a list.

A list (a b c) is represented (stored internally) as three cons-cells: (cons 'a (cons 'b (cons 'c '()). Note that the last pair has '() in its cdr.
Series of cons-cells whose last cdr is '() is printed as a list by the printer. The example is thus printed as (a b c).
Let's look at: (cons 'a '(a b)).
The list '(a b) is represented as (cons 'a (cons 'b '()). This means that
(cons 'a '(a b)) produces: (cons 'a (cons 'a (cons 'b '())).
Let's look at: (cons '(a b) 'a).
The list '(a b) is represented as (cons 'a (cons 'b '()). This means that
(cons (cons '(a b) 'a)) produces (cons (cons 'a (cons 'b '()) 'a).
Note that this series does not end in '(). To show that the printer uses dot notation. ( ... . 'a) means that a value consists of a series of cons-cells and that the last cdr contains 'a. The value (cons (cons 'a (cons 'b '()) 'a) is thus printed as '((a b) . a).

cons is just a pair data type. For example, (cons 1 2) is a pair of 1 and 2, and it will be printed with the two elements seperated by a dot like (1 . 2).
Lists are internally represented as nested conses, e.g. the list (1 2 3) is (cons 1 (cons 2 (cons 3 '())).

Related

Can you get dot representation using 'list' command in LISP?

I understand that by using cons we could have something like :
> (cons 'b 'c)
(B . C)
And that happens because the cell is split into two and the values are B and C.
My question is, can you get the same result using list?
You can't get list to return a dotted list, because "the last argument to list becomes the car of the last cons constructed" in the returned list.
But, you can get list* to return a dotted list. With the list* function, the final argument becomes the cdr of the last cons, so:
CL-USER> (list* 'a '(b))
(A B)
CL-USER> (list* 'a 'b '())
(A B)
CL-USER> (list* 'a 'b)
(A . B)
CL-USER> (list* 'a '(b c))
(A B C)
CL-USER> (list* 'a 'b '(c))
(A B C)
CL-USER> (list* 'a 'b 'c '())
(A B C)
CL-USER> (list* 'a 'b 'c)
(A B . C)
For example, (list* 'a 'b 'c '()) and (list 'a 'b 'c) are both equivalent to:
CL-USER> (cons 'a (cons 'b (cons 'c '())))
(A B C)
But (list* 'a 'b 'c) is equivalent to:
CL-USER> (cons 'a (cons 'b 'c))
(A B . C)
And, (list* 'a 'b) is equivalent to:
CL-USER> (cons 'a 'b)
(A . B)
No you can't, because a list is a list of cons cells whose last cdr is nil. The Lisp printer knows the convention and doesn't print a dot in that case.
;; a cons cell
CL-USER> (cons 'b 'c)
(B . C)
[o|o]--- c
|
b
;; two cons cells, ending with a symbol: a dot.
CL-USER> (cons 'b (cons 'c 'd))
(B C . D)
;; several cons cells, ending with a symbol: still a dot (at the last cons cell):
CL-USER> (cons 'b (cons 'c (cons 'd (cons 'e 'f))))
(B C D E . F)
;; two cons cells, ending with nil: no dot.
CL-USER> (cons 'b (cons 'c nil))
(B C) ;; and not (B C . NIL)
[o|o]---[o|/]
| |
b c
;; with the list constructor:
CL-USER> (list 'b 'c)
(B C)
https://lispcookbook.github.io/cl-cookbook/data-structures.html#building-lists-cons-cells-lists

Lisp: ordered union of two lists

I am trying to make a function that returns the union of two lists in an ordered manner.
Here is my code:
(defun setunion (lst1 lst2)
(cond
((null lst1) lst2)
((null lst2) lst1)
((member (car lst2) lst1)
(setunion lst1 (cdr lst2)))
(t (append (setunion lst1 (cdr lst2))
(list (car lst2))))))
(print (setunion '(a b c) '(a c d e f a)))
This returns (A B C F E D) but the output I am looking for is (A B C D E F). How can I change my code to return the right output?
Thanks!
EDIT: I figured it out I think. I made a helper function that removes the duplicates of list 2 and reverses it as well as remove the duplicates of list 1.
(defun help (lst1 lst2)
(setunion (remove-duplicates lst1 :from-end t) (reverse(remove-duplicates lst2 :from-end t))))
(print (help '(b c b d) '(a d e a)))
This gives me the output (B C D A E) which is what I'm looking for.
OK, so basically all you want to do is remove duplicates over all lists, and the elements should be in order of first appearance. You could append all lists, then remove duplicates from the end:
(defun set-union (&rest lists)
(remove-duplicates (reduce #'append lists)
:from-end t))
If what you want is the union of a bunch of lists such that elements in the lists occur in the order they occur in the lists, working from the left, then here is one fairly natural way of doing that. I'm not sure if this is what I'd write in real life. It has the advantage that:
it's easy to see what is happening;
it doesn't rely on hairy standard CL functions.
It has the disadvantage that it requires tail-call elimination to work with long lists (and some people regard code which works like this not to be idiomatic CL).
(defun union-preserving-order (&rest ls)
;; Union of a bunch of lists. The result will not contain
;; duplicates (under EQL) and elements will occur in the order they
;; occur in the lists, working from the left to the right. So
;; (union-preserving-order '(a b) '(b a c)) will be (a b c), as will
;; (union-preserving-order '(a b) '(c b a)), while
;; (union-preserving-order '(b a) '(a b c) '(c d)) will be (b a c
;; d).
(upo/loop (first ls) (rest ls) '()))
(defun upo/loop (lt more accum)
;; LT is the list we're working on, MORE is more lists for later,
;; ACCUM is the list we're building (backwards). In real life this
;; would be a local function in UNION-PRESERVING-ORDER.
(if (null lt)
;; Finished this list
(if (null more)
;; no more lists: we're done
(nreverse accum)
;; more lists, so pick the first of them and loop on that
(upo/loop (first more) (rest more) accum))
;; not finished this list, so loop on it
(upo/loop (rest lt) more
;; Either the next element of this list is already in
;; the accumulator, or it's not and we need to add it.
(if (member (first lt) accum)
accum
(cons (first lt) accum)))))
Here's a version which uses explicit iteration but otherwise does the same trick.
(defun union-preserving-order (&rest ls)
;; Union of a bunch of lists. The result will not contain
;; duplicates (under EQL) and elements will occur in the order they
;; occur in the lists, working from the left to the right. So
;; (union-preserving-order '(a b) '(b a c)) will be (a b c), as will
;; (union-preserving-order '(a b) '(c b a)), while
;; (union-preserving-order '(b a) '(a b c) '(c d)) will be (b a c
;; d).
(let ((accum '()))
(dolist (l ls (nreverse accum))
(dolist (e l)
(pushnew e accum)))))
Finally here's a dirty hack which builds the results forwards. Without proof I think this is as good as you can do in terms of performance without resorting to some clever lookup structure like a hash-table to check whether you've seen elements already.
(defun union-preserving-order (&rest ls)
;; Union of a bunch of lists. The result will not contain
;; duplicates (under EQL) and elements will occur in the order they
;; occur in the lists, working from the left to the right. So
;; (union-preserving-order '(a b) '(b a c)) will be (a b c), as will
;; (union-preserving-order '(a b) '(c b a)), while
;; (union-preserving-order '(b a) '(a b c) '(c d)) will be (b a c
;; d).
(let ((results '()) ;results we'll return
(rlc nil)) ;last cons of results
(dolist (l ls results)
(dolist (e l)
(unless (member e results)
(if (not (null rlc))
(setf (cdr rlc) (list e)
rlc (cdr rlc))
(setf rlc (list e)
results rlc)))))))

how to map an element in a list to a value from other list in LISP

I am new to lisp programming and i am trying to think about the below operation.
(extract '(0 1 0) '(a b c)) give us '(a b a)
(extract '(1 1 1 ) '(a b c)) gives us '(b b b)
how can i think about this and how to solve it.
As Chris Jester-Young described, it just returns elements from second list at indexes in first list. Writing such a function is very easy:
(defun extract (list-1 list-2)
(mapcar (lambda (n) (nth n list-2)) list-1))
CL-USER>(extract '(0 1 0) '(a b c))
(A B A)
CL-USER>(extract '(1 1 1 ) '(a b c))
(B B B)
If there no such index, it'll give you NIL in that place.
CL-USER> (extract '(1 100 1 ) '(a b c))
(B NIL B)
But this won't work on nested structures (trees). If you want it to return elements of list-2 shaped in the structure of list-1, you can use a simple maptree helper function, then do the same thing:
(defun maptree (fn tree)
(cond
((null tree) tree)
((atom tree) (funcall fn tree))
(t (cons
(maptree fn (first tree))
(maptree fn (rest tree))))))
(defun extract* (list-1 list-2)
(maptree (lambda (n)
(nth n list-2)) list-1))
CL-USER> (extract* '(3 (2 1 (0))) '(a b c d))
(D (C B (A)))
(extract a b) returns a copy of a where each element is replaced by the element of b in that position.

Apply and keyword arguments in lisp

I can use keyword parameters in LISP
(member 'a '(a b c) :test #'eq)
However, when I tried to use apply to invoke member method
(apply #'member 'a '(a b c) :test #'eq)
I have error message as follows:
MEMBER: keyword arguments in (:TEST) should occur pairwise
[Condition of type SYSTEM::SIMPLE-PROGRAM-ERROR]
The solution was
(apply #'member 'a '(a b c) '(:test eq))
Whereas without the keyword arguments
(apply #'member 'a '((a b c)))
What's the logic behind this? Why '(:test #'eq) raises an error?
ADDED
This is the reason why I asked this question.
I have code from ANSI Common Lispbook page 103.
(defun our-adjoin (obj lst &rest args)
(if (apply #'member obj lst args)
lst
(cons obj lst)))
When I tried (our-adjoin 'a '(a b c)) it returns the result (A B C), but the our-adjoin can't be translated as (apply #'member 'a '(a b c)), because it will raise an error (as is asked in Apply and keyword arguments in lisp).
What I can think about is that the value from &rest args is given to make something like (apply #member 'a '(a b c) '()) not to raise an error.
apply expects its final argument to be a list. That is,
(apply #'foo (list 1 2 3)) == (foo 1 2 3)
(apply #'member 'a '(a b c) :test #'eq) == ??? ; is an error - #'eq isn't a list
I don't know what apply is making of #'eq (a function) where a list is expected, but that's the problem.
You might be looking for funcall instead of apply:
(funcall #'foo 1 2 3) == (foo 1 2 3)
(funcall #'member 'a '(a b c) :test #'eq) == (member 'a '(a b c) :test #'eq)
Edit: (apply #'member 'a '(a b c))
This is the same as
(member 'a 'a 'b 'c)
which of course is nonsense. Think of apply as "expanding" its last argument.
Edit 2: The our-adjoin code
(our-adjoin 'a '(a b c) :test #'eq)
;; is equivalent to
(if (apply #'member 'a '(a b c) (list :test #'eq))
lst
(cons obj lst))
;; is equivalent to
(if (member 'a '(a b c) :test #'eq) ...)
(our-adjoin 'a '(a b c))
;; is equivalent to
(if (apply #'member 'a '(a b c) (list)) ...) ; (list) == nil
;; is equivalent to
(if (member 'a '(a b c)) ...)
So your hypothesis (that the equivalent was (apply #'member 'a '(a b c) '())) is correct. (FYI, there is no difference between nil, 'nil, (), '(), and (list).)
APPLY is provided so that we can call functions with a computed argument list.
APPLY has the following syntax:
apply function &rest args+ => result*
the first parameter is a function
then several arguments, at least one, where the last argument needs to be a list

How to do ((A.B).(C.D)) in lisp

I'm trying to figure out how to do this using cons:
((A . B) . (C . D))
where (A . B) and (C . D) are in each cons cell
I've tried doing this (cons (cons 'a 'b) (cons 'c 'd)) but it gives me this:
((A.B) C . D)
I also tried this: (cons (cons 'a 'b) (cons (cons 'c 'd) ())) but it gives me this:
((A . B) (C . D))
Any idea how to achieve this?
The first one is what you want. They're equivalent. You can verify like this:
1 ]=> (cons (cons 'a 'b) (cons 'c 'd))
;Value 11: ((a . b) c . d)
1 ]=> (car (cons (cons 'a 'b) (cons 'c 'd)))
;Value 12: (a . b)
1 ]=> (cdr (cons (cons 'a 'b) (cons 'c 'd)))
;Value 13: (c . d)
Remember a list is a cons cell. The "car" is the head element of the list or the first half of the cons cell, and the cdr is the rest of the list, or the second element of the cons cell.
Another way to verify that they're equivalent:
1 ]=> '((a . b) . (c . d))
;Value 14: ((a . b) c . d)
Just look at what you get back when you enter in a literal ((A . B) . (C . D)):
* '((a . b) . (c . d))
((A . B) C . D)
There is a defined algorithm the Lisp printer uses to print out data structures built from pairs. Basically, you can't ever get a cons to be printed as a dotted pair inside parentheses when it is the CDR of another cons.
However, it is possible to re-configure the printer so that you get the behavior you are seeking, via SET-PPRINT-DISPATCH:
(set-pprint-dispatch 'cons
(lambda (stream object)
(format stream "(~W . ~W)" (car object) (cdr object))))
* '((a . b) . (c . d))
((A . B) . (C . D))
* (cons (cons 'a 'b) (cons 'c 'd)) ;The same object
((A . B) . (C . D))
Although in spite of that it would frankly be better in the long run if you got comfortable with reading the default behavior.
I'm not quite sure what you mean... I agree with the above comment that the last line of your code resembles the first, which you are matching against.
Here's a decent general resource for you anyhow: http://www-2.cs.cmu.edu/~dst/LispBook/
What you're looking for isn't possible because of how lists are represented in Lisp. When you create a list, you are creating a series of cons cells, where the car of the cell is the value of that element in the list, and the cdr is a reference to the next cons cell. Your desired cell, ((A . B) . (C . D)) means "create a cons cell where the car is (A . B) and the cdr is (C . D)". That is equivalent to a list where the first element is (A . B), second element is C and the tail of the list is D, or ((A . B) C . D).