Inconsistent box-and-pointer diagrams in SICP - scheme

Structure and Interpretation of Computer Programs (SICP)'s box-and-pointer diagrams in Figures 3.16 and 3.17 don't appear equivalent (purely with respect to value, not memory) even though it says they are. ("When thought of as a list, z1 and z2 both represent "the same" list, ((a b) a b))", pg. 258)
(define x (list 'a 'b))
(define z1 (cons x x))
(define z2 (cons (list 'a 'b) (list 'a 'b)))
SICP diagrams the pair z1 like this:
and z2 like this:
The arrows in the pair, z1, don't both seem to be pointing to the entire pair, x. They don't even point to the same thing, despite both having received the same (memory and value) pair.
I would evaluate the first diagram as (a b), and the second as ((a b) a b)
I could guess that each arrow is actually pointing to the entire pair, x, but in figure 2.3 on page 98:
it very clearly points to an entire box by either pointing to the side or in between two items.
Am I understanding box-and-pointer diagrams incorrectly or something else entirely?

You're reading too much into it. :-) If it points into the box anywhere, assume it's a pointer to that cons cell. You cannot specifically point to the car or cdr portion of it.

Your last assumption is correct. The dot indicates where the pointer value is, the whole double box the arrow is pointing at is the target. It doesn't matter if it's pointing on the side, top middle, top left or top right. It's the whole pair that is the "address" of the object.
You can't point to a part of an object without accessing its part with car and cdr. The second you do that you have whatever it was pointed to and not a indirect pointer. (car '(a b)) ; ==> a and a doesn't have any essence of the list that still is pointing to it until it is garbage collected.
We could illustrate it like this instead:
[=#1|#3|#2]
[=#2|#3|()]
[=#3|a |#4]
[=#4|b |()]
The first value with =# is the location of the box itself, while the next two are car and cdr. Above, x points to the address #3 and z1 to #1. Let's make z2
[=#5|#6|#8]
[=#6|a |#7]
[=#7|b |()]
[=#8|#9|()]
[=#9|a |#10]
[=#10|b |()]
As you can see, z2 uses two more cons than z1 since it doesn't reuse the same object as both elements of its list, but uses individual similar-looking lists.
In the drawings, both car and cdr of z1 point to the same list x. z2 points to two different lists, but the elements in those lists are the same.
The reason for this is that symbols are singletons. Thus, you only have one symbol object for a and evaluating 'a in two different places will both point to the same a. Other singletons are #f, #t and ()
cons always creates a fresh pair and list is just a procedure that cons together the arguments. Thus the same code (list 'a 'b) two places in the expression makes two different objects that just look the same.
(eq? (car z1) (cdr z1)) ; ==> #t same object
(eq? (car z2) (cdr z2)) ; ==> #f not same object
(equal? (car z2) (cdr z2)) ; ==> #t they look the same, but they are not the same. (created at different places)
Quoted data can be seen as created all at once before the program starts. Thus this is undefined.
(eq? '(a b) '(a b)) ; ==> #t or #f (undefined)
(eq? '(b c) (cdr '(a b c))) ; ==> #t or #f (undefined)
The reason is that Scheme is allowed, but not obligated, to reuse data the same way as with the structure z1.

Related

Scheme box and pointer cyclic list

I am trying to understand what is happening when writing this code by drawing it with the box and pointer method but cant quite get it. Anybody that could help?
(define bar (list 'a 'b 'c 'd 'e))
(set-cdr! (cdddr bar) (cdr bar))
My idea:
Also I don't know how to start to draw a diagram for the code under, I cant see where the points and boxes for (car) need to be.
(define bah (list 'bring 'a 'towel))
(set-car! bah (cdr bah))
This is the initial situation:
And this is the final situation:
If you try to print bah, it is printed as a three element list, whose first element is a two element list:
((a towel) a towel)
But in fact the two structures are shared, so that, for instance, if you do:
(set-car! (cddr bah) 'handkerchief)
bah will be printed as:
((a handkerchief) a handkerchief)

Racket count occurrences using `map`

Write a Racket function count-occurrences that consumes two lists of symbols and produces a list of
natural numbers measuring how many times items in the first list occur in the second list. For example:
(count-occurrences (list 'a 'b 'a 'q) (list 'r 'a 'b 'e 'b 'g))
=> (list 1 2 1 0)
I've been struggling with this question - how do I use map to do it, since for this question it's specified we can't use recursion.
My original idea was to do the following:
(define (count-occurrences los1 los2)
(map
(length (filter (lambda (x) (symbol=? x (first los1))) los2))
los1))
but using length here can only get us the number 'a occurred, instead of going into recursion. and for abstract functions there can only be one argument for the inside function, so I'm totally lost.
If ... x ... is an open formula, i.e. an expression which references an unbound variable x, wrapping it in a lambda form makes it a function in x, like so:
(lambda (x) ... x ... )
where x becomes bound by that lambda form; a parameter to this so called lambda function, which is to say, an anonymous function introduced by a lambda form.
So, the solution for your troubles is quite simple: recognize that
(length
(filter (lambda (x)
(symbol=? x (first los1)))
los2))
should actually be
(length
(filter (lambda (x)
(symbol=? x y))
los2))
where y refers to each of the elements of los1 in turn, not just the first one; and that it is then an open formula in y – that is to say, y is unbound, free, there. So we must capture it, and make it bound, by ... yes, enclosing this expression in a lambda form, thereby making it a function in y! Like so:
(lambda (y)
(length
(filter (lambda (x)
(symbol=? x y))
los2)))
And this is what gets mapped over los1.
With this simple tweak, your code becomes a correct, working function definition.
Does this fit your requirements and restrictions?
(define (count-occurrences lst1 lst2)
(map (lambda (e1)
(count (lambda (e2) (eq? e1 e2))
lst2))
lst1))
A good way to keep track of keys and values is with a hash-table. While it is possible to write count-occurrences using map and passing a lambda, being explicit may make it easier to see what is going on.
;;; list list -> list
;;;
(define (count-occurrences keys values)
;; Create data structure
(define ht (make-hash))
;; Initialize data structure with keys
;; Set the value of each key to zero
;; Since we have not started counting
(for ([k keys])
(hash-set! ht k 0))
;; Iterate over values and
;; Increment hash table if
;; When value is a key
(for ([v values])
(if (hash-has-key? ht v)
(hash-set! ht v (+ (hash-ref ht v) 1))
null))
;; Iterate over keys and
;; Create list of values
(for/list ([k keys])
(hash-ref ht k)))
Since recursion is prohibited, explicitly looping may make for more maintainable/readable code than an implicit loop. Besides, the variations of for are worth knowing. Hash tables have the advantage that duplicate keys read the same value and there is no need to track the same key twice.
One of the engineering advantages of using for rather than map is that it is easier to reason about the running time. The running time for this code is 2m + n where m is keys and n is values. Solutions using map will typically be m * n. There's nothing inherently wrong with that. But it is worth recognizing.

Why does `(= (car x) 'z)` work?

I was stumbling through the Arc tutorial when I got sort of confused with this:
Quoted from the Arc Tutorial:
Like Common Lisp assignment, Arc's = is not just for variables, but
can reach inside structures. So you can use it to modify lists:
arc> x
(a b)
arc> (= (car x) 'z)
z
arc> x
(z b)
But lisp is executed recursively, right? It says that car returns the first value in a list. So:
arc> (car x)
a
which makes sense, but then why isn't (= (car x) 'z) equal to (= a 'z), which would result in:
arc> a
z
arc> x
(a b) ; Note how this hasn't changed
but it doesn't. Instead, it appears that (= (car x) 'z) seems to have the effects of (= x (list 'z (car (cdr x)))):
arc> (= x '(a b))
(a b)
arc> (= (car x) 'z)
z
arc> x
(z b)
...
arc> (= x '(a b))
(a b)
arc> (= x (list 'z (car (cdr x))))
(z b)
arc> x
(z b)
So why exactly does (= (car x) 'z) work that way and what is it that I'm missing here?
Note: this is my first introduction to LISP.
= is a special operator, it's not a function. So its arguments are not evaluated according to the normal recursive process. The first argument is treated specially, it identifies a place to assign to, not the value already in that place. It may have to evaluate subexpressions within it to find the place, but once it gets to the place, it stops evaluating. The second argument will be evaluated normally, to get the value to assign there.
= appears to be an assignment operator in Arc, the equivalent in Common Lisp would be setf. In this case, (car x) returns the place that is to be modified:
? (defparameter x '(a b))
X
? x
(A B)
? (setf (car x) 'z)
Z
? x
(Z B)
See also here.
= is a macro or rather "special operator", which is just a fancy name for built-in macro. Macros' arguments (unlike functions' arguments) aren't evaluated at all, so the = operator gets (car x) unevaluated ==> it get's the list (car x) itself! Now, that = operator contains miniature code walker that traverses the list (car x) and figures out what place would be read from if the list was evaluated. And assigns to that place.
What does it assign? The result of evaluating the second argument, it evaluates that one manually.
So the effective evaluation scheme for = is in fact
(= <unevaluated-argument> <evaluated-argument>)
EDIT:
Another example of macro or special operator is if. in (if <cond> <a> <b>), if starts being evaluated first and gets arguments <cond>, <a> and <b> raw - unevaluated. Then it manually evaluates <cond> and depending on the result, it either evaluates <a> or <b> and returns result of that. If everything was really evaluated recursively, you could never have working if or cond or loop or short-circuit and and or and so on...
NOTE: = is probably (= I suppose) a macro and not special operator, at least its equivalent setf in common lisp is a macro. I doubt that P. Graham embedded = directly into the compiler. But it's not really important to know.
If you have the book "ANSI Common Lisp", there is such sentence in chapter 3.3 Why Lisp Has No Pointers:
One of Secrets to understanding Lisp is to realize that variables have values in the same way that lists have elements. As conses have pointers to their elements, variables have pointers to their values.
If x is assigned a list:
arc> (= x '(a b))
(a b)
It formulates as such, the variable x points to a list. The 1st position of the list points to the symbol a and the 2nd points to the symbol b:
When car of x is assigned with 'z in (= (car x) 'z), simply the 1st position points the new symbol z.
Finally, in the expression (= a 'z), a variable a is assigned and thus points to the symbol z

Error: Can't bind name in null syntactic environment

I'm currently going through exercise 1.3 of the sicp book. Here's the description of the problem:
Define a procedure that takes three numbers as arguments and returns
the sum of the squares of the two larger numbers.
I tried to solve it with the following code
(define (square x) (* x x))
(define (sq2largest a b c)
((define large1 (if (> a b) a b))
(define small (if (= large1 a) b a))
(define large2 (if (> c small) c small))
(+ (square large1) (square large2))))
When I ran it in mit-scheme, I got the following error:
;Can't bind name in null syntactic environment: large1
#[reserved-name-item 13]
Googling this error doesn't yield many results. Does anyone know what's wrong with my code? (I'm not familiar with Scheme)
I'll try to break down the structure of your sq2largest procedure:
The basic structure is:
(define (sq2largest a b c)
; Body)
The Body you wrote is:
((define large1 (if (> a b) a b)) ; let this be alpha
(define small (if (= large1 a) b a)) ; let this be bravo
(define large2 (if (> c small) c small)) ; let this be charlie
(+ (square large1) (square large2)) ; let this be delta) ; This parentheses encloses body
So, the Body is structured as:
(alpha bravo charlie delta)
Which translates to: "Pass bravo, charlie and delta as arguments to alpha."
Now, alpha is being told to take a bunch of arguments, but inside the namespace reserved for large1, no provision was made for any argument... i.e. scheme encounters a null syntactic environment where it cannot bind any variable.
Parentheses are significant in Scheme (and most, if not all, Lisps) because they define the scope of a procedure and enforce[1] the order of application of operations.
[1] "No ambiguity can arise, because the operator is always the leftmost element and the entire combination is delimited by the parentheses." http://mitpress.mit.edu/sicp/full-text/sicp/book/node6.html
You have too many brackets. If you took out the extra brackets around the internal defines, things should work a lot better.

How to print a string in backward, in scheme?

I know if I write my scheme code in the following way and type in (word ‘(a b c)), it will out put the list in the same order. Could you please tell me if there was a way I can print it out in opposite order. Ex- (list ‘c ‘b ‘a).
it needs to be the user's input I print out in opposite order. So, I can't call it (reverse '(a b c)). since the user input can be something like '(x y z).
Thanks a lot.
(define(word x )
(if(null? x) x
(cons(car x)(word (cdr x)))))
(word '(a b c))
(list 'a 'b 'c)
(reverse '(a b c))
will reverse your string. However I suspect that this is probably homework and you are supposed to write your own reverse function.
If so, can you reverse an empty list? If you have a list and have the reverse of the rest of the list, can you get the reverse of the whole list? Can you see how to make a function that reverses the list from these pieces?
Is this what you want?
(list->string (reverse (string->list "market")))
"tekram"
Thanks all for your information and help. I found a way to do it. just in-case there was anyone else looking.
(define (word lis)
(if (null? lis)
'()
(append (word (cdr lis))
(list (car lis)))))
Hint: cons creates a list composed of its first argument followed by its second argument. Right now, you're using it to create a list of the first element followed by the same function applied to the rest of the elements, and that creates a list in the same order as it was.
What do you suppose would happen if you created a list of the same function applied to the rest of the elements followed by the first element?

Resources