SICP- the expression of tree data structure in LISP [duplicate] - lisp

I've started learning Scheme, for fun mostly, and because I've never used a functional language before. I chose Scheme because I wanted to read SICP for a long time.
Anyway, I'm currently learning about lists, and before that I learned about cons, car and cdr. And there's an example that creates a list of lists with cons, like this :
(cons (list 1 2) (list 3 4))
The resulting list is ((1 2) 3 4), which doesn't make sense to me, I would expect ((1 2)(3 4)) to be the result (a list made out of two lists). Why does it behave like that? I realize that if I were to use car, I would get (1 2), and cdr I'd get (3 4) becaue cdr always returns "the rest", but I don't understand why the list isn't made of two lists?

You get a list with (1 2) as the first element (the car) and (3 4) as the rest (the cdr) because the first argument to cons is the first element of the list and the second argument is a list containing the remaining items.
This closely resembles the structure of a list: each node of a (proper) list contains an element and a list containing all other element. cons creates one such node.
If the second argument to cons would become the second element of the list, how would you create a list with three arguments? You'd have to make cons variardic at which point, it'd just be another name for list.
If you want to create a list of lists use (list (list 1 2) (list 3 4)).

(list (list 1 2)
(list 3 4))
is the same as
(cons (list 1 2)
(cons (list 3 4)
'()))
Which results in
((1 2) (3 4))
which can also be written as
((1 . (2 . ()))
.
((3 . (4 . ()))
.
()))

list A: [ | ]
1 [ | ]
2 /
list B: [ | ]
3 [ | ]
4 /
======================
(cons A B)
[ | ]
[ | ] [ | ]
1 [ | ] 3 [ | ]
2 / 4 /
A graphic representation of the inner structures can help us to visualize the problem.
And this will help some more:
[ | ]
X [ | ]
3 [ | ]
4 /
Do you see the pattern? The above is the list (X 3 4). That's the reason (cons A B) draws only the car part as a separate list and not the cdr.

Because a cons-cell is not a list of two elements, the two are often confused. If (a . b) is a cons cell, then (a . (b . ())) is a list of two elements. Any list safe the empty list specifically is a cons cell whose car field contains the first element and whose cdr field contains the list which contains the remaining elements. A list is thus simply a binary tree whose right-most leaf is the special constant () or nil depending on your dialect.
Which is why (cons 0 '(1 2 3)) evaluates to (0 1 2 3) and not (0 (1 2 3)) we create a cons cell whose car is 0, and whose cdr is (1 2 3), so a list (0 1 2 3).

Here's a really simple explanation:
(define (x)
(cons (list 1 2) (list 3 4)))
we know that these two conditions must be true:
(car x) = (1 2) #car = first element
(cdr x) = (3 4) #cdr = rest of the elements
the only way to satisfy this is x = ((1 2) 3 4).
________________________________________________________________________________________________________
x = ((1 2)(3 4)) is incorrect because:
(car x) = (1 2)
(cdr x) = ((3 4))
See there is an extra bracket/list created for (cdr x).
x = ((1 2)(3 4)) is actually a list of lists:
list( list(1 2) list(3 4)) = ((1 2)(3 4))

Related

Why is a literal quoted list not the same as a list built by list constructors

(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)

Exercise about substitution in nested lisp [duplicate]

I’m trying to write a function with two arguments of this type:
substitutions (list_one, list_two)
list_one has always this form (letters can change according to the input):
(1 ((1 2 ((1 2 r) (3 2 t) (4 3 c))) (3 4 ((5 6 y) (5 7 i)))))
list_two has always this form (numbers can change according to the input):
(2 3 4 5 6)
I want to substitute in this way:
r-> 2
t -> 3
c -> 4
y -> 5
i -> 6
Can you help me please?
A not so efficient solution is to first find a list of all the letters in the fist tree structure (the first list) and then to LOOP over the results calling SUBST repeatedly.
To find the list of non numeric atoms in the first list (the 'letters') you need to traverse the tree structure (le first list) recurring both on the FIRST and on the REST of the list.
Hope it helps.
MA
If the lists are proper you can iterate them with the loop macro and pop off the arguments in the accessible free variable:
(defun template-replace (template replacements)
(labels ((iterate (template)
(loop :for element :in template
:collect
(cond ((consp element) (iterate element))
((symbolp element) (pop replacements))
(t element)))))
(iterate template)))
(template-replace '(1 rep (4 rep (9 rep)) rep) '(foot inch mm multiplied))
; ==> (1 foot (4 inch (9 mm)) multiplied)

Substitutions in Common Lisp

I’m trying to write a function with two arguments of this type:
substitutions (list_one, list_two)
list_one has always this form (letters can change according to the input):
(1 ((1 2 ((1 2 r) (3 2 t) (4 3 c))) (3 4 ((5 6 y) (5 7 i)))))
list_two has always this form (numbers can change according to the input):
(2 3 4 5 6)
I want to substitute in this way:
r-> 2
t -> 3
c -> 4
y -> 5
i -> 6
Can you help me please?
A not so efficient solution is to first find a list of all the letters in the fist tree structure (the first list) and then to LOOP over the results calling SUBST repeatedly.
To find the list of non numeric atoms in the first list (the 'letters') you need to traverse the tree structure (le first list) recurring both on the FIRST and on the REST of the list.
Hope it helps.
MA
If the lists are proper you can iterate them with the loop macro and pop off the arguments in the accessible free variable:
(defun template-replace (template replacements)
(labels ((iterate (template)
(loop :for element :in template
:collect
(cond ((consp element) (iterate element))
((symbolp element) (pop replacements))
(t element)))))
(iterate template)))
(template-replace '(1 rep (4 rep (9 rep)) rep) '(foot inch mm multiplied))
; ==> (1 foot (4 inch (9 mm)) multiplied)

Scheme Macros - Pair in the transform but list as output?

Let's say I have the following macro in R5RS Scheme:
(define-syntax pair-test
(syntax-rules ()
((_ (a b . c))
(quote (a b . c)))))
The macro transforms an input pair to an output pair, as one would expect:
(pair-test (1 2 . 3))
==> (1 2 . 3)
I can also pass a list to the macro, as allowed by the spec. However, the output is a list instead of a pair:
(pair-test (1 2 3))
==> (1 2 3)
What exactly is going on here? Why is the output a list instead of a pair?
Could c be (3 . ()) in the second case? I'm not positive but that would make sense to me. And then quoting (a b . c) would be (1 2 . (3 . ())) which is (1 2 . (3)) and (3) is a proper list, so (1 2 3)?
To see what's happening here, you need to know that a list in Scheme is a recursive chain of pairs of elements and other lists. Any data that follows the form of a list will always be printed as a list. Once you know how basic lists are constructed, you'll be able to see what's happening inside your macro.
Pairs in Scheme can be created using the . operator, or using the cons function. Here's a simple pair of numbers:
(quote (1 . 2))
==> '(1 . 2)
(cons 1 2)
==> '(1 . 2)
To create a list of 1 in Scheme, you can make a pair out of something and the empty list:
(quote (1 . ()))
==> '(1)
(cons 1 (list))
==> '(1)
A list of 2 is a pair of something of something on the left side, and a list of 1 on the right side. Likewise, a list of 3 is one element paired with a list of 2:
(quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons 1 (cons 2 (cons 3 (list))))
==> '(1 2 3)
To see what your macro is doing, you can rearrange the (quote (a b . c)) to be more explicit:
(quote (a . (b . c)))
(cons (quote a) (cons (quote b) (quote c)))
Now you can see that this form looks very similar to when you're constructing a list. If (quote c) results in a list, then the whole expression will be a list. In the case of (pair-test (1 2 3)), c becomes (3 . ()):
(quote (a . (b . c)))
==> (quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons (quote a) (cons (quote b) (quote c)))
==> (cons '1 (cons '2 '(3 . ())))
==> '(1 2 3)
This value is printed by the REPL as a list because it is a "proper list". Each right side (cdr) is a list, all the way up to the empty list at the end, so this value perfectly follows list form. The REPL assumes you'd like to see the result as a list, so it gets printed without a . present.
You'd see '(1 2 . 3) for (pair-test (1 2 . 3)), because this is how the REPL prints "improper lists". If the last element in the chain of pairs is not the empty list, the value is considered an "improper list", and will be printed differently:
(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)

Why does using cons to create a pair of two lists produce a list and two elements?

I've started learning Scheme, for fun mostly, and because I've never used a functional language before. I chose Scheme because I wanted to read SICP for a long time.
Anyway, I'm currently learning about lists, and before that I learned about cons, car and cdr. And there's an example that creates a list of lists with cons, like this :
(cons (list 1 2) (list 3 4))
The resulting list is ((1 2) 3 4), which doesn't make sense to me, I would expect ((1 2)(3 4)) to be the result (a list made out of two lists). Why does it behave like that? I realize that if I were to use car, I would get (1 2), and cdr I'd get (3 4) becaue cdr always returns "the rest", but I don't understand why the list isn't made of two lists?
You get a list with (1 2) as the first element (the car) and (3 4) as the rest (the cdr) because the first argument to cons is the first element of the list and the second argument is a list containing the remaining items.
This closely resembles the structure of a list: each node of a (proper) list contains an element and a list containing all other element. cons creates one such node.
If the second argument to cons would become the second element of the list, how would you create a list with three arguments? You'd have to make cons variardic at which point, it'd just be another name for list.
If you want to create a list of lists use (list (list 1 2) (list 3 4)).
(list (list 1 2)
(list 3 4))
is the same as
(cons (list 1 2)
(cons (list 3 4)
'()))
Which results in
((1 2) (3 4))
which can also be written as
((1 . (2 . ()))
.
((3 . (4 . ()))
.
()))
list A: [ | ]
1 [ | ]
2 /
list B: [ | ]
3 [ | ]
4 /
======================
(cons A B)
[ | ]
[ | ] [ | ]
1 [ | ] 3 [ | ]
2 / 4 /
A graphic representation of the inner structures can help us to visualize the problem.
And this will help some more:
[ | ]
X [ | ]
3 [ | ]
4 /
Do you see the pattern? The above is the list (X 3 4). That's the reason (cons A B) draws only the car part as a separate list and not the cdr.
Because a cons-cell is not a list of two elements, the two are often confused. If (a . b) is a cons cell, then (a . (b . ())) is a list of two elements. Any list safe the empty list specifically is a cons cell whose car field contains the first element and whose cdr field contains the list which contains the remaining elements. A list is thus simply a binary tree whose right-most leaf is the special constant () or nil depending on your dialect.
Which is why (cons 0 '(1 2 3)) evaluates to (0 1 2 3) and not (0 (1 2 3)) we create a cons cell whose car is 0, and whose cdr is (1 2 3), so a list (0 1 2 3).
Here's a really simple explanation:
(define (x)
(cons (list 1 2) (list 3 4)))
we know that these two conditions must be true:
(car x) = (1 2) #car = first element
(cdr x) = (3 4) #cdr = rest of the elements
the only way to satisfy this is x = ((1 2) 3 4).
________________________________________________________________________________________________________
x = ((1 2)(3 4)) is incorrect because:
(car x) = (1 2)
(cdr x) = ((3 4))
See there is an extra bracket/list created for (cdr x).
x = ((1 2)(3 4)) is actually a list of lists:
list( list(1 2) list(3 4)) = ((1 2)(3 4))