I'm using R5RS standart of Scheme language.
Please have a look at these two objects:
(1 (2 . 3))
(1 2 . 3)
Do they have the same memory representations? Like this (A):
Or the first one is different? Like this (B):
So... What is correct?
They're different. The first list is constructed like this, corresponding to the "B" figure:
(cons 1
(cons (cons 2 3)
'()))
> '(1 (2 . 3))
Whereas the second list structure is constructed like this, which corresponds to the "A" figure:
(cons 1
(cons 2 3))
> '(1 2 . 3)
Also notice that the second one is not a proper list (meaning: a list that ends with null).
Related
I am currently working my way through Berkely's summer 2011 CS3L course and am struggling to understand Box and Pointer Diagrams. How to build them and how to interpret them.
The instructions provided are here.
However, I am still not "getting it."
I understand that lists are combinations of pairs and that the cdr of a pair may point to another pair. I also understand that the pair that the cdr points to may be another list. I just don't understand how to draw it all out in a diagram.
For reference, here is an example of a problem I am being given is:
(define cal
(list (append (list (cons (list 1 2) (cons 3 '())))
(list (cons 4 (cons 5 '()))))
6
7))
Given a code like the one above, I am suppose to draw the box and pointer diagram and then be able to say what combination of car and cdr is necessary to get any given number in the list.
Again, for reference, below is the diagram I should have been able to come up with:
To reiterate, what I'm looking for is a video or article that may explain the building of box and pointer diagrams more clearly.
Thank you in advance for anyone willing to point me in the right direction.
[Note that this answer is not encouraging you to cheat: if you are doing a course which requires you to be able to draw box & pointer diagrams then you should be able to do that, not have a program do it for you. But the program can help you learn.]
One good approach to learning how box & pointer diagrams work is to be able to talk to a program which knows how to draw them. In Lisp's long ago golden age we had wonderful conversational interfaces on our Lisp machines which let graphics and text be intermingled, along with nice graph-drawing programs from which tools could easily be built to do this. Using such tools you could construct various structures out of conses and get the program to draw diagrams for you, and thus you got a good handle on how the structures work.
Well ... it turns out Lisp's golden age is now. If you use Racket (and you can use Racket if you are not already using it) then there is a very wonderful package called sdraw which does this. It's not bundled with the Racket distribution, but to install it you can either use DrRacket's package manager or just do
raco pkg install --auto sdraw
which will install it. Now you can (in a DrRacket window, this won't work in a terminal session) simply talk to the Racket REPL and get it to draw cons trees for you:
By simply interacting with the language and letting it draw things for you then you can get a really good feel for how the various structures hang together.
This answer uses Common Lisp for its examples, but it is not fundamentally different in Scheme. Note also that you can play with sdraw.lisp in Common Lisp (e.g. with CCL or SBCL programs) if you want to see how printing the diagram can actually be implemented.
You first have to be clear about the result you want to print, which might be difficult when the source contains cons/list/append operations. Also, since the source code is also a tree of cons-cells, you have to take care not to mix the source with the value obtained after its evaluation.
So it all starts with evaluating the form correctly.
Evaluate cal
Let's first evaluate the expression. Below, I also mention drawing the boxes directly from the input expression, but IMO it helps to detail that intermediate step.
The result is the same in Scheme and Common Lisp, after recursively evaluating all expressions:
((((1 2) 3) (4 5)) 6 7)
Here is how you could ask the system to trace the computation, in Common Lisp. First of all, know that you cannot trace standard functions like list, etc. So let's shadow them in a custom package with simple wrappers:
(defpackage :so
(:use :cl)
(:shadow #:list #:cons #:append))
(in-package :so)
(defun list (&rest args) (apply #'cl:list args))
(defun cons (&rest args) (apply #'cl:cons args))
(defun append (&rest args) (apply #'cl:append args))
Then, in the REPL, go to that package:
CL-USER> (in-package :so)
#<PACKAGE "SO">
Ask to trace those functions:
SO> (trace list append cons) ;; the shadowing ones
(LIST CONS APPEND)
Now, you can enter the value of cal directly, but this time the symbols being used are the one we asked to trace.
SO> (list (append (list (cons (list 1 2) (cons 3 '())))
(list (cons 4 (cons 5 '()))))
6
7)
The environment then evaluates the form and prints how each function is called and what results it returns.
0: (SO::LIST 1 2)
0: LIST returned (1 2)
0: (SO::CONS 3 NIL)
0: CONS returned (3)
0: (SO::CONS (1 2) (3))
0: CONS returned ((1 2) 3)
0: (SO::LIST ((1 2) 3))
0: LIST returned (((1 2) 3))
0: (SO::CONS 5 NIL)
0: CONS returned (5)
0: (SO::CONS 4 (5))
0: CONS returned (4 5)
0: (SO::LIST (4 5))
0: LIST returned ((4 5))
0: (SO::APPEND (((1 2) 3)) ((4 5)))
0: APPEND returned (((1 2) 3) (4 5))
0: (SO::LIST (((1 2) 3) (4 5)) 6 7)
0: LIST returned ((((1 2) 3) (4 5)) 6 7)
((((1 2) 3) (4 5)) 6 7)
Vizualize as cons cells
It can be helpful to view lists as chains of cons-cells, i.e. turn (a b c) into (a . (b . (c . nil))). Let's define a helper function:
(defun consprint (x)
(if (consp x)
(format nil
"(~a . ~a)"
(consprint (car x))
(consprint (cdr x)))
(prin1-to-string x)))
Here is the result:
SO> (consprint '((((1 2) 3) (4 5)) 6 7))
"((((1 . (2 . NIL)) . (3 . NIL)) . ((4 . (5 . NIL)) . NIL)) . (6 . (7 . NIL)))"
Draw: a term rewriting approach
Use a recursive, bottom-up approach to draw it.
Definition.: Here I define a leaf as a cons-cell that has atoms in both its CAR and its CDR slots: e.g. (0 . NIL) and (X . Y) are both leaves, but not ((0 . 1) . 2). Note that this includes improper lists, something I am relying on to explain the drawing method when I replace subterms by symbols.
((((1 . (2 . NIL)) . (3 . NIL)) . ((4 . (5 . NIL)) . NIL)) . (6 . (7 . NIL)))
^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^
Above I underlined all leaves: you can easily draw those boxes, and label them with symbols (A, B, ...).
Here below I replace the original cells with the names of their associated boxes, and again underline the new leaves:
((((1 . A) . B) . ((4 . C) . NIL)) . (6 . D))
^^^^^^^ ^^^^^^^ ^^^^^^^
Then, when there is a symbol representing a box, draw an arrow to that box. For example, you define a box named E that corresponds to (1 . A), so you draw [1/x] and connect the x to box A.
You obtain:
(((E . B) . (F . NIL)) . G)
Now, consider (E . B): its car is a symbol, so the box you need to draw has no value, but an outgoing arrow from the CAR slot that points to the E cell (just like its CDR points to B).
You repeat this process until termination. The rest is visual layout, where typically boxes that are just linked lists of atoms are laid out horizontally.
Directly drawing from expressions
Presumably the original exercise wants you to draw boxes right from the original expression. The same can be done as above, working upward from leaf expressions and replacing their values by symbols denoting existing boxes.
A cons maps directly to a box.
a list is just a repeated application of cons, and you can go quickly by drawing as many boxes as there are elements.
append in practice makes a copy of all but the last list in arguments, but when drawing you can "mutate" the existing boxes. For each existing box, keep following the CDR until you reach a box with no arrow in cdr, and link that box to the next one in the arguments, thus chaining the different boxes together.
It can be interesting to also draw the actual, purely functional version of append to see how structure sharing and garbage collection work.
Starting from the code, you can work from the top level down. Given:
(define cal
(list (append (list (cons (list 1 2) (cons 3 '())))
(list (cons 4 (cons 5 '()))))
6
7))
you can see that the first level is a list containing three elements: a complex object, a 6, and a 7. This can be represented by three cons cells:
Now you just need to figure out what the car of the first cons cell points to. Looking back at the code, this points to a list that is comprised of two lists, appended together. If you look at the parentheses, you can see that the first call to list is taking only one argument, so this will create a list containing one element.
When two lists are appended, the nil that closes the first list is replaced by a pointer to the front of the second list so:
The first list of the two to be appended is created by this code:
(list (cons (list 1 2) (cons 3 '())))
Here, the list (1 2) is consed to the front of the list (3) to create a new list. This is a list of two elements where the car of the list points to the list (1 2) and the cdr of the list is (3). We can go ahead and draw the boxes for this layer:
And since the car of the last layer just points to the list (1 2), we can fill that in:
Now, the second argument to the append function is also a list containing only one element, so:
That single element is the result of (cons 4 (cons 5 '())), which is just the list (4 5), so we can finally finish our box diagram by pointing to this list from the car of the last cons cell:
Try starting from the inside out, just as the interpreter will. Draw the diagram for, say, (cons 3 '()) - pretty simple, right? Now, should anything point to it? Yes, it is the cdr of (cons (list 1 2) (cons 3 '())). So, when you draw the diagram for that larger expression, make sure its cdr points to the first sub-diagram you drew. To finish drawing this larger expression, you'll also need to draw a diagram for (list 1 2) - just as easy as where you started.
Work your way outwards from there - the append operation is the trickiest part, but the instructions you linked explained how append works.
Forget lists. There are no lists. There are only pairs.
(define cal
(list (append (list (cons (list 1 2) (cons 3 '())))
(list (cons 4 (cons 5 '()))))
6
7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL))) ; (list 1 2)
(define B (cons 3 NIL)) ; (cons 3 '())
(define C (cons 5 NIL)) ; (cons 5 '())
(define cal
(list (append (list (cons A B))
(list (cons 4 C)))
6
7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))
(define B (cons 3 NIL))
(define C (cons 5 NIL))
(define D (cons A B))
(define E (cons 4 C))
(define cal
(list (append (list D)
(list E))
6
7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))
(define B (cons 3 NIL))
(define C (cons 5 NIL))
(define D (cons A B))
(define E (cons 4 C))
(define F (list D E)) ; (append (list D) (list E))
(define cal
(list F
6
7))
=
(define NIL '())
(define A (cons 1 (cons 2 NIL)))
(define B (cons 3 NIL))
(define C (cons 5 NIL))
(define D (cons A B))
(define E (cons 4 C))
(define F (cons D (cons E NIL))) ; (list D E)
(define cal
(cons F
(cons 6
(cons 7 NIL))))
Each cons is a box. Each name is a pointer.
And that's all.
I'm trying to learn LISP. I got my way around functions and I wanted to test myself with some.
I was trying to write a function that can remove an element from a list in a given index.
This seems pretty straightforward, but I can't manage to do it.
Example: I have the list (20 8 13 10) and I want to remove the number at index 2.
How would I go about something like this?
It's very easy. This is the base case:
(remove-nth 0 '(2 3)) ; => (3)
And the default case:
(remove-nth 1 '(1 2 3)) ; ==
(cons 1 (remove-nth 0 '(2 3)))
The only thing left for you to do is to actually implement it!
There is a third case. What if the list is nil? In the strictest sense you cannot do the job and you should signal an error or perhaps there isn't anything to do so it's ok to then have it as a base case that evaluates to '() so that (remove-nth 5 '(1 2)) ; ==> (1 2)
I need some help understanding the syntax on how to append a number into a list, i'm doing this from user input via the console so this elements have to be entered in recursively. So for ever number that is entered, the list must grow for each element (only numbers) added.
Here is the code I am working with, the problem lies in the second conditional. Right now this works but only creates an empty list of each number I put in, so the results would be
>12
>202
>30
()()()
zero input: stopping list
(define (inputlist)
(let ((applist list))
(let ((inpt (read)))
(cond
((= inpt 0)(newline) (display "zero input: stopping list"))
;;OLD((number? inpt) (cons inpt applist) (display (applist))(inputlist))
((number? inpt) (append (applist)(list inpt)) (display (applist))(inputlist))
(else
display "Not a number")))))
I understand why cons is not doing what I need it to be doing, but is there a similar functionality to appending each read in element to a pre-existing list?
EDIT: I've gotten closer what i've needed to do but still with the same results, i am now appending upon my applist with a list i create via every input, though it is still resulting in as many empty lists as I input.
SECOND EDIT: I've realized why it's printing multiple ()'s is because it's being called off the stack when 0 is entered, so i'm sure it's not working because the appending isn't working as intended, i've displayed the applist on the 0 conditional and it returns one null list.
A simple way to append an element to the end of a list while looping would be to do call append and update the reference to the list afterwards:
(set! applist (append applist (list inpt)))
Notice that you have several misplaced parentheses - in your code some are missing, some are unnecessary. In Scheme () means function application, and you have to be careful where you put those brackets.
Also, be aware that append doesn't modify the initial list, it creates a new one, and if you need to refer to it, you have to store it somewhere (that's why I'm doing a set! above).
There are more serious errors with you logic. The conditions are in the wrong order (you have to test if the input is a number before asking if it's zero), and you forgot to loop if something other than a number is entered. Also, if we pass along the list as a parameter to the loop, we won't have to do an ugly set!. Try this instead, it's closer to what you were aiming for:
(define (inputlist)
(let loop ((applist '()))
(let ((inpt (read)))
(cond ((not (number? inpt))
(display "not a number")
(newline)
(loop applist))
((zero? inpt)
(display "zero input: stopping list"))
(else
(let ((new-applist (append applist (list inpt))))
(display new-applist)
(newline)
(loop new-applist)))))))
As mentioned in the comments, bear in mind that appending at the end of a list inside a loop in general is a bad idea. It's ok for learning purposes, but in real-life code, you'd cons at the head of the list and reverse it at the end - this is more efficient.
Note that (cons x xs) where x is an element and xs is a list produces a new list which has x as its first element.
Here is one way to use cons to add an element in the end of a list:
Example:
Add 4 to (1 2 3)
1. Reverse the list: (3 2 1)
2. Add 4 to the front: (4 3 2 1)
3. Reverse: (1 2 3 4)
> (reverse (cons 4 (reverse (list 1 2 3)))
(1 2 3 4)
A function that uses this principle:
(define (cons-to-back x xs)
(reverse (cons x (reverse xs))))
> (cons-to-back 4 (list 1 2 3))
(1 2 3 4)
An alternative is to use append which appends the elements of two lists:
> (append '(1 2 3) '(4 5 6))
(1 2 3 4 5 6)
All we need to do, is to the the element into a list before using append:
> (append '(1 2 3) (list 4))
'(1 2 3 4)
Alternative definition of cons-to-back:
(define (cons-to-back x xs)
(append xs (list x)))
So I am new to using Scheme/Guile and have an assignment where I must take 2 inputs; a simple variable and a list.
I then add the variable to each number in the list and print it out. I have got it to load but when I enter this:
(add 1 (1 2 3))
I get this error:
Backtrace:
39: 0* [add 1 ...
39: 1* [1 2 3]
standard inout:39:8: In expression (1 2 3):
standard input:39:8:wrong type to appy: 1
ABORT: (misc-error)
Here is the code that I currently have.
(define a (list a))
(define (add y a)
(define x 0)
(while (< x (length a))
(display (+ y (car a)))
(newline)
(set! a (cdr a))
(set! x (+ x 1))
)
)
My question is:
How do I get the list to work in the parameter? I have looked around online but havent found much to fix this problem.
Many thanks ahead of time for any help you can give me.
You're getting an error because (1 2 3) tells it to call the function 1 with two arguments, 2 and 3. To create a list containing 1, 2 and 3, use (list 1 2 3).
Do you really intend to write a procedure in such an imperative way? It looks not very Scheme-like. Evaluating your procedures in GNU Guile yields many error messages about unbound variables etc. set! is eval for beginners of Scheme ;) :) (SICP treats assignment extensively in chapter 3). You can do it much easier in functional style without the side-effects of set! and display.
If you are already aware about mapping and high-order functions, you could do something like this:
(define (add x)
(lambda (y) (+ x y)))
(map (add 1) (list 1 2 3))
===> (2 3 4)
If not, write a recursive procedure yourself:
(define (add-to-list x list)
(if (null? list)
'()
(cons (+ x (car list))
(add-to-list x (cdr list)))))
(add-to-list 1 '(1 2 3))
===> (2 3 4)
In order to learn thinking recursively, consult books like SICP, HTDP or "The litte Schemer".
From reading introductory material on Lisp, I now consider the following to be identical:
(list 1 2 3)
'(1 2 3)
However, judging from problems I face when using the quoted form in both Clojure and Emacs Lisp, they are not the same. Can you tell me what the difference is?
The primary difference is that quote prevents evaluation of the elements, whereas list
does not:
user=> '(1 2 (+ 1 2))
(1 2 (+ 1 2))
user=> (list 1 2 (+ 1 2))
(1 2 3)
For this reason (among others), it is idiomatic clojure to use a vector when describing a literal collection:
user=> [1 2 (+ 1 2)]
[1 2 3]
In Common Lisp, quoted objects are constant literal data. The data is not evaluated. You should not modify this data, as the consequences are undefined. Possible consequences are: modification of shared data, attempt to modify read-only data, an error might be signalled, it might just work, shared data, ...
Literal lists:
'(1 2 3)
Above is a constant list, which will be constructed by the reader and evaluating to itself, because it is quoted. If it appears in Lisp code, a compiler will embed this data somehow in the FASL code.
(quote (1 2 3)) is another way to write it.
(list 1 2 3)
this is a call of the Common Lisp function LIST with three arguments 1, 2 and 3. Each of the arguments will be evaluated. Since they are numbers, they evaluate to themselves. When evaluated the result is a fresh new list (1 2 3).
Data sharing in compiled code
Imagine in a Lisp file the following four definitions:
(defparameter *list1* (list 1 2 3))
(defparameter *list2* (list 1 2 3))
(defparameter *list3* '(1 2 3))
(defparameter *list4* '(1 2 3))
Then we compile and load the file.
! (eq *list3* *list4*) now may evaluate to either T or NIL depending on the implementation and compiler settings !
Reason: in Common Lisp the Lisp compiler may share structure of literal lists (!) if they are similar. The compiler detects that here the lists are similar and will allocate only one list. Both variables *list1* and *list2* the will point to this one list.
All other EQ (object equality) comparisons of two of the above lists will return NIL.
Notations for some other data structures:
'(1 . 2) and (cons 1 2) ; cons cell
'#(1 2 3) and (vector 1 2 3) ; vector
'#S(FOO :a 1 :b 2) and (make-foo :a 1 :b 2) ; structure
One is the literal data and the other is a function call that constructs such a data structure.
Quoted lists (e.g. '(1 2 3)) should be treated carefully (generally as read-only). (see SO answers When to use 'quote in Lisp and When to use 'quote in Lisp).
(list 1 2 3) will "cons" up a fresh list, independent of all others.
You can see an example of a pitfall of using quoted lists in the manual for nconc.
And, as you probably know, when you call 'list - the arguments will obviously be evaluated versus the contents of a quoted list. And 'quote takes a single argument, versus 'lists variable number of arguments.
(list (+ 1 2) 3) --> (3 3)
(quote ((+ 1 2) 3)) --> ((+ 1 2) 3)
Their relation can be analogous to function invocation with 'function name' and funcall.
When you have no idea what function you'll get at runtime, you use funcall.
When you have no idea what element you may get at runtime, your use list.
For people like me who get confused because of existence of backquote and count it as quote tacitly.
backquote is not quote
It's a reader-macro that expands into quote, list or others:
(macroexpand ''(1 2));=> '(1 2)
(macroexpand '`(1 2));=> '(1 2)
(macroexpand '`(1 ,2));=> (list 1 2)
(macroexpand '`(1 ,#foo));=> (cons 1 foo)
(macroexpand '`(1 ,#foo 2));=> (cons 1 (append foo '(2)))