From 558c22ffdfa69afbcc5b139ded2c07a9eea499a7 Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Mon, 3 Aug 2015 20:11:09 -0700 Subject: [PATCH 1/9] forloops added but markdown is broken --- .../section05 Vectors.md | 158 +++++++++++++----- 1 file changed, 112 insertions(+), 46 deletions(-) diff --git a/textbook/chapter20 9 - Mutable Data and Vectors/section05 Vectors.md b/textbook/chapter20 9 - Mutable Data and Vectors/section05 Vectors.md index 3876cca..a5e0b67 100755 --- a/textbook/chapter20 9 - Mutable Data and Vectors/section05 Vectors.md +++ b/textbook/chapter20 9 - Mutable Data and Vectors/section05 Vectors.md @@ -6,38 +6,36 @@ lists are great, they have one big disadvantage--referring to the nth element of a list takes Θ(n) time because we have to `cdr` n times. We want a way to be able to refer to the nth element of a sequence while -taking constant time. In Scheme, **vectors** provide a mechanism of doing +taking constant time. In Racket, [vectors](http://docs.racket-lang.org/reference/vectors.html) provide a mechanism of doing this. If you've programmed in Java or other C-like languages, it's essentially the same idea as an array. Unfortunately, vectors have a drawback. In a linked list (which is essentially the list structure you've been working with so far this semester), adding to the end of a list can be done Θ(1) time, since all we have to do is `cons` to -the end of a list. However, adding to a vector takes Θ(n) time, where n is the +the start of a list. However, adding to a vector takes Θ(n) time, where n is the length of the vector. ## How Vectors Work -How do vectors work? What is this black magic that allows you to reference -elements in constant time? Well, it turns out that it's not, in fact, black -magic. +How do vectors work? How can we access the elements of a vector in constant time? When you create a vector, you must specify the size of the vector you would -like. Creating a vector of size n sets aside a chunk of memory n size long. -Since we know the address of the first "block" of memory, we can add k to that -address to get the kth element of the vector. This is how we can access any -element in constant time! +like. Creating a vector of size n sets aside a chunk of memory n size long, so that +the elements of a vector are stored side by side in memory. Since we know the address +in memory of the first item in the vector, we can add k to that address to get the kth +element of the vector. This is how we can access any element in constant time! -The downside is that in order to get all the elements in a single chunk of +The downside is that in order to get all the elements side by side in a single chunk of memory, we have to allocate the chunk all at once. This is why adding an -element to a vector takes Θ(n) time -- we would have to allocate a new chuck -of memory (i.e. create a new array) and copy all of the old elements over! +element to a vector takes Θ(n) time -- we would have to allocate a new chunk +of memory (i.e. create a new array of size n+1) and copy all of the old elements over! ## vector primitives **NOTE: Vectors index from 0.** -By this we mean the first element is referred to as the 0th element. That +What this means is that the first element is referred to as the 0th element. That means that in the vector `#(1 2 3 4)`, 1 is at the 0th index, 2 is at the 1st index, and so on. @@ -51,7 +49,7 @@ Some of the vector primitives are analogous to the primitives for lists: But what about `cons` and `append`? Since adding an element to a vector takes Θ(n) time, there are no primitives to add to the end of a vector. There are, -however, different constructers. +however, different constructors. As discussed before, one of the main weaknesses of vectors is that we have to declare how long the vector is going to be when we create it. Therefore, the @@ -66,8 +64,8 @@ in order to set the nth element of a vector to a certain value. This is similar to `set-car!` and `set-cdr!` Note: There exist procedures `list->vector` and `vector->list` that convert -between the two types. However, in the lab and homework, you probably won't be -using these procedures since the whole point of this lab is to learn vectors +between the two types. However, in the lab and homework, you won't be +using these procedures since the whole point of this lesson is to learn vectors :) ## Vector programming @@ -109,46 +107,119 @@ that is how our function knows when to stop. iteration. At the beginning of the semester, we mentioned that recursion is usually considered more elegant than iteration. Hopefully you now see why. -## vectors vs lists +## For-loops +As we've just seen, using recursive iteration on vectors is cumbersome. In order +to make our lives easier, we can use [for-loops](http://docs.racket-lang.org/guide/for.html) +with vectors. A for-loop automates an iterative process for us. -Here are some comparisons between the running times for list and vector -procedures. +For-loops have the following general form: + + (for ([id sequence-expr] ...) + body ...+) + + +Here, `id` is the name of a new variable, `sequence-expr` is some sequence (such as a list or a vector), and body is what we'd like +to be executed for every iteration. The `body` of the for-loop gets executed as many times as the length of the `sequence-expr` specifies. +For each iteration of the body, the `id` variable gets bound to the next element in the sequence. + +Let's clear all this up with an example. Consider the following for-loop: + + + (for ([i '(1 2 3)]) + (display i)) + + +The first time around, the variable `i` gets bound to the number 1. We then display the variable `i`, so 1 gets displayed. Since we've finished +executing the body,the for-loop goes on to the next iteration and binds `i` to 2, and then evaluates the body, so 2 gets displayed. The final iteration binds +`i` to 3, and displays 3. + +You can also have multiple variable ids in your forloops. Consider the following for-loop: -**operation** -**list** -**vector** -nth element + (for ([i '(1 2 3)] [k '(4 5 6)]) + (display i) + (display k)) + -`(list-ref lst n), `Θ(n) +The first iteration of the for-loop binds the variable `i` to 1 and `k` to 4, and then executes the body, displaying 1 and 4. The second iteration binds `i` to 2 +and `k` to 5, and so on. Be careful if you use more than one id in your for-loops though; the for-loop will stop iterating after one of the sequences has been emptied. +For example, the following for-loop will never bind `k` to 7: -`(vector-ref vec n), `Θ(1) + (for ([i '(1 2 3)] [k '(4 5 6 7)]) + (display i) + (display k)) -adding an element +In most cases, it's tedious to have to write out all of the values in our `sequence-expr`. This is why Racket has a procedure [in-range](http://docs.racket-lang.org/reference/sequences.html#%28def._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._in-range%29%29), which returns a sequence of numbers in a specified range. Here are some examples of uses of `in-range`: -`cons, `Θ(1) + -> (in-range 3) + ;; returns a sequence of integers from 0 to 2 (does not include the 3) + (0 1 2) + -> (in-range 1 5) + ;; returns a sequence of integers from 1 to 4 (does not include the 5) + (1 2 3 4) + -> (in-range 0 3 0.5) + ;; returns a sequence of numbers from 0 to 3 separated by 0.5 (does not include the 3) + (0 0.5 1 1.5 2 2.5) -No primitive procedure, Θ(n) -length +To see how for-loops make dealing with vectors much easier, let's rewrite `map` using a for-loop: -`(length lst), `Θ(n) + (define (vector-map fn v) + (let ((newvec (make-vector (vector-length v)))) + (for ([i (in-range (vector-length v))]) + (vector-set! newvec i (fn (vector-ref v i)))) + newvec)) + -`(vector-length vec), `Θ(1) +You can compare this code to our recursive code for vector-map and see how for-loops make our code much cleaner. + +## vectors vs lists + +Here are some comparisons between the running times for list and vector +procedures. + + + + + + + + + + + + + + + + + + + + + + + +
operationlistvector
nth element(list-ref lst n), Θ(n)(vector-ref vec n), Θ(1)
adding an elementcons, Θ(1)No primitive procedure, Θ(n)
length(length lst), Θ(n)(vector-length vec), Θ(1)
There's no one best way to represent sequences--vectors and lists are good for different things. If you're going to be adding and subtracting a lot of -elements from your sequence, it's best to use a list because `cons` is in +elements from your sequence, it's best to use a list because `cons` runs in constant time. On the other hand, if you're going to have a fixed number of elements but are going to be changing a lot of them, vectors are better -because `vector-ref` is constant time. +because `vector-ref` runs in constant time. ## example: shuffling Suppose we have a deck of cards, and we want to shuffle it. What would be the best sequence to represent this? -First, let's use a list and use mutation to shuffle the deck. +First, let's use a list and use mutation to shuffle the deck destructively. (define (list-shuffle! lst) @@ -164,22 +235,17 @@ First, let's use a list and use mutation to shuffle the deck. This does what we want, but it's very slow--Θ(n2) time. In fact, any list- -based solution would take Θ(n2) time because it takes Θ(n) time to find a +based solution would take Θ( n2 ) time because it takes Θ(n) time to find a random element, and we have to do that n times. Let's try the same thing, but use a vector instead of a list. - - (define (vector-shuffle! vec) - (define (loop n) - (if (= n 0) - vec - (let ((index (random n)) - (temp (vector-ref vec (- n 1)))) - (vector-set! vec (- n 1) (vector-ref vec index)) - (vector-set! vec index temp) - (loop (- n 1)) - (loop (vector-length vec))) + (define (vector-shuffle! vec) + (for ([i (in-range (vector-length vec))]) + (let ((index (random (+ i 1))) + (temp (vector-ref vec i))) + (vector-set! vec i (vector-ref vec index)) + (vector-set! vec index temp)))) This is essentially the same algorithm, but performed on a vector instead of a From 45047edf51afa82c6fb8014fb686b78562d9e6ba Mon Sep 17 00:00:00 2001 From: Allen Guo Date: Mon, 3 Aug 2015 21:32:43 -0700 Subject: [PATCH 2/9] Fix OS X issue with publishing caused by .DS_Store files --- publish.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/publish.py b/publish.py index f8400b1..9dc0fb2 100755 --- a/publish.py +++ b/publish.py @@ -141,6 +141,9 @@ def publish_chapter(self, chapter_num): chapter_title = re.sub('chapter\d* ', '', chapter_dir) chapter_toc = self.generate_chapter_toc(section_files, chapter_title) + # Only convert Markdown files in the secion + section_files = filter(lambda s: s.lower().endswith('.md'), section_files) + # Build the sections that comprise this chapter for section in section_files: input_path = os.path.join('textbook/', chapter_dir, section) From 8c337d0ccc51ca10f2871cf4fc7e60e73cd74dba Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Sat, 8 Aug 2015 23:57:49 -0700 Subject: [PATCH 3/9] tables sections modified for racket --- .../section04 Representing Tables.md | 151 ++++++++++-------- 1 file changed, 88 insertions(+), 63 deletions(-) diff --git a/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md b/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md index f10ce9a..3045a96 100755 --- a/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md +++ b/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md @@ -5,11 +5,9 @@ and, given 2 keys, can fetch the desired data. We can use mutable lists to represent this data structure by first building a 1 dimensional table and extending the idea. -![](http://www.9ori.com/store/media/images/ea7b57534c.jpg) +## Before we Start: assoc -## Before we Start:assoc - -Before we dive right in to tables, we have to explore another Scheme compound +Before we dive right into tables, we have to explore another Racket compound procedure, `assoc,` which will play a huge role. `assoc` accepts a `key` and a list of pairs, and returns the first pair that has `key` as its `car`. If no such pairs exist, it returns `#f`. Look at the series of examples below to @@ -33,47 +31,63 @@ understand what `assoc` does. ## Definiton -assoc is defined as: +`assoc` is defined as: (define (assoc key records) (cond ((null? records) false) ((equal? key (caar records)) (car records)) (else (assoc key (cdr records))))) + +Since this lesson deals with mutable data, we'll be using `massoc` with +our tables. The procedure `massoc` has the same functionality as `assoc`, +but it works on mutable lists. -## 1 Dimensional Table +## One Dimensional Table In a 1D table, values are stored under a single key. A table will be designed -as a list of pairs. The pairs' `car` hold the keys for each value. +as a list of pairs. Each pair's `car` hold the key associated with each value. ![](http://mitpress.mit.edu/sicp/full-text/book/ch3-Z-G-22.gif) In the above table, the breakdown between the keys and values can be seen below. -KeysValues - -a - -1 - -b - -2 - -c - -3 + + + + + + + + + + + + + + + + + + +
KeysValues
a1
b2
c(length lst), O(n)
Why does our table point to a pair that doesn't contain any key-value pair? We designed our table so that the first pair holds the symbol `*table*` which -signifies that the current list structure we're looking at is a table. +signifies that the current list structure we're looking at is a table. This +is similar to the idea of tagged data from Lesson 6. (define (make-table) - (list '*table*)) + (mcons '*table* '())) ## Lookup @@ -85,9 +99,9 @@ value stored under that key). (define (lookup key table) - (let ((record (assoc key (cdr table)))) + (let ((record (massoc key (mcdr table)))) (if record - (cdr record) + (mcdr record) false))) >(lookup 'b table) ;table refers to the table made above @@ -103,12 +117,12 @@ To insert a key-value pair in a table you follow these steps: (define (insert! key value table) - (let ((record (assoc key (cdr table)))) + (let ((record (massoc key (mcdr table)))) (if record - (set-cdr! record value) - (set-cdr! table - (cons (cons key value) (cdr table))))) - 'ok) + (set-mcdr! record value) + (set-mcdr! table + (mcons (mcons key value) (mcdr table))))) + 'okay) ## 2 Dimensional Table @@ -132,6 +146,11 @@ We can put them into one big table: ![](http://mitpress.mit.edu/sicp/full-text/book/ch3-Z-G-23.gif) +Our constructor for 2D tables is the same as our constructor for 1D tables: + + (define (make-table) + (mcons '*table* '())) + ## Lookup To find a value in a 2D table, you will need 2 keys. The first key is used to @@ -141,11 +160,11 @@ that subtable. (define (lookup key-1 key-2 table) - (let ((subtable (assoc key-1 (cdr table)))) + (let ((subtable (massoc key-1 (mcdr table)))) (if subtable - (let ((record (assoc key-2 (cdr subtable)))) + (let ((record (massoc key-2 (mcdr subtable)))) (if record - (cdr record) + (mcdr record) #f)) #f))) @@ -154,25 +173,25 @@ that subtable. To insert into a 2D table, you also need 2 keys. The first key is used to try and find the correct subtable. If a subtable with the first key doesn't exist, -make a new subtable. If the table exists, use the exact same algorithm we have -for the 1 dimensional` insert!` . +make a new subtable. If the subtable exists, use the exact same algorithm on this +subtable that we used in our 1D table's `insert!`. (define (insert! key-1 key-2 value table) - (let ((subtable (assoc key-1 (cdr table)))) + (let ((subtable (massoc key-1 (mcdr table)))) (if subtable - (let ((record (assoc key-2 (cdr subtable)))) + (let ((record (massoc key-2 (mcdr subtable)))) (if record - (set-cdr! record value) - (set-cdr! subtable - (cons (cons key-2 value) - (cdr subtable))))) - (set-cdr! table - (cons (list key-1 - (cons key-2 value)) - (cdr table))))) - 'ok) + (set-mcdr! record value) + (set-mcdr! subtable + (mcons (mcons key-2 value) + (mcdr subtable))))) + (set-mcdr! table + (mcons (mlist key-1 + (mcons key-2 value)) + (mcdr table))))) + 'okay) ## Local Tables @@ -182,41 +201,45 @@ argument. This enables us to use programs that access more than one table. Another way to deal with multiple tables is to have separate `lookup` and` insert!` procedures for each table. We can do this by representing a table procedurally, as an object that maintains an internal table as part of its -local state. When sent an appropriate message, this "table object'' supplies +local state. When sent an appropriate message, this table "object" supplies the procedure with which to operate on the internal table. Here is a generator for two-dimensional tables represented in this fashion: (define (make-table) - (let ((local-table (list '*table*))) + (let ((local-table (mlist '*table*))) (define (lookup key-1 key-2) - (let ((subtable (assoc key-1 (cdr local-table)))) + (let ((subtable (massoc key-1 (mcdr local-table)))) (if subtable - (let ((record (assoc key-2 (cdr subtable)))) + (let ((record (massoc key-2 (mcdr subtable)))) (if record - (cdr record) + (mcdr record) false)) false))) (define (insert! key-1 key-2 value) - (let ((subtable (assoc key-1 (cdr local-table)))) + (let ((subtable (massoc key-1 (mcdr local-table)))) (if subtable - (let ((record (assoc key-2 (cdr subtable)))) + (let ((record (massoc key-2 (mcdr subtable)))) (if record - (set-cdr! record value) - (set-cdr! subtable - (cons (cons key-2 value) - (cdr subtable))))) - (set-cdr! local-table - (cons (list key-1 - (cons key-2 value)) - (cdr local-table))))) - 'ok) + (set-mcdr! record value) + (set-mcdr! subtable + (mcons (mcons key-2 value) + (mcdr subtable))))) + (mset-cdr! local-table + (mcons (mlist key-1 + (mcons key-2 value)) + (mcdr local-table))))) + 'okay) (define (dispatch m) (cond ((eq? m 'lookup-proc) lookup) ((eq? m 'insert-proc!) insert!) (else (error "Unknown operation -- TABLE" m)))) dispatch)) + +If this is confusing to you, review Lesson 8's sections on local state variables. +The idea of a dispatch procedure that interprets messages delivered to your table +is very similar to the [bank account example](http://www.cs61as.org/textbook/local-state-variables.html#sub4). ## Get & Put @@ -229,15 +252,17 @@ under 2 keys using the procedures `get` and `put`. (get ) -We can now define these procedures using our tables! +We can now define these procedures using our "local" tables, as defined right above! (define operation-table (make-table)) (define get (operation-table 'lookup-proc)) (define put (operation-table 'insert-proc!)) +Remember that `(operation-table 'lookup-proc)` and `(operation-table 'insert-proc!)` both +return procedures! -`Get` takes as arguments two keys, and `put` takes as arguments two keys and a +The procedure `get` takes as arguments two keys, and `put` takes as arguments two keys and a value. Both operations access the same local table, which is encapsulated within the object created by the call to `make-table`. From 13b8e01a0cf624e067a08585bfeaeb2597237eee Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Sun, 9 Aug 2015 00:09:30 -0700 Subject: [PATCH 4/9] fixed minor typos in tables section --- .../section04 Representing Tables.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md b/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md index 3045a96..60c2cab 100755 --- a/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md +++ b/textbook/chapter20 9 - Mutable Data and Vectors/section04 Representing Tables.md @@ -8,7 +8,7 @@ extending the idea. ## Before we Start: assoc Before we dive right into tables, we have to explore another Racket compound -procedure, `assoc,` which will play a huge role. `assoc` accepts a `key` and a +procedure, `assoc,` which will play a huge role. The procedure `assoc` accepts a `key` and a list of pairs, and returns the first pair that has `key` as its `car`. If no such pairs exist, it returns `#f`. Look at the series of examples below to understand what `assoc` does. @@ -75,7 +75,7 @@ below. c - (length lst), O(n) + 3 @@ -92,7 +92,7 @@ is similar to the idea of tagged data from Lesson 6. ## Lookup -To extract information from a table we use the `lookup` procedure, which takes +To extract information from a table, we use the `lookup` procedure, which takes a key as argument and returns the associated value (or false if there is no value stored under that key). @@ -114,6 +114,8 @@ To insert a key-value pair in a table you follow these steps: 1. If key is already in the list, just update the value 2. Otherwise, make a new key-value pair and attach it to the table + +We define `insert!` as follows: (define (insert! key value table) @@ -129,7 +131,7 @@ To insert a key-value pair in a table you follow these steps: In a 2 dimensional table, each value is specified by 2 keys. We can construct such a table as a 1 dimensional table in which each key identifies a subtable. -Say we have 2 tables: "math" and "letters" with the following key-value pairs. +Say we have 2 tables: `math` and `letters` with the following key-value pairs. math: From 1ed49e992bf568d8c840c92d64d5cef611a6a048 Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Sun, 16 Aug 2015 23:29:03 -0700 Subject: [PATCH 5/9] lesson 11 proofread except for homework --- .../section01 Lesson 11 Intro.md | 46 +++--- .../section02 Eval.md | 150 ++++++++++-------- .../section03 Apply.md | 145 +++++++++-------- .../section04 Running the Evaluator.md | 37 ++--- .../section06 Python Interpreter.md | 21 +-- .../section07 Homework 11.md | 10 +- 6 files changed, 219 insertions(+), 190 deletions(-) diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md b/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md index dd5240d..56fc01e 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md @@ -1,13 +1,14 @@ -## metacircular evaluator +## Metacircular Evaluator -Do you remember Scheme-1 in Lesson 6? Now it's time to explore how Scheme +Do you remember Racket-1 in Lesson 6? Now it's time to explore how Racket evaluates expressions! -## prerequisites and what to expect +## Prerequisites and What to Expect -A good understanding of how Scheme-1 works will be helpful in this chapter. -The materials covered in this lesson would be quite different from the other -materials covered so far. So be prepared! +A good understanding of how Racket-1 works will be helpful in this chapter. You should +also be comfortable with the environment model of evaluation from Lesson 8. +The material covered in this lesson will be quite different from the other +material covered so far, so be prepared! ## Readings @@ -17,15 +18,12 @@ These are the relevant readings for this lesson: * [SICP 4.1.1-6](http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-26.html) * [Lectures Notes](http://www-inst.eecs.berkeley.edu/~cs61as/reader/notes.pdf#page=78) -## what is an evaluator? +## What Is An Evaluator? -![](http://www.codingthewheel.com/img/some_assembly.gif) - -So far, we learned how to write procedures that output what we want. Once we -define those procedures and type them in the Scheme prompt, we get the value. +So far, we have learned how to write procedures that output what we want. Once we +define those procedures and type them in the Racket prompt, we get the value. But have you wondered how those procedures actually get evaluated and work in -Scheme (you probably did in Lesson 6)? How does Scheme know what the -expression means? Well, there's an evaluator. +Racket? How does Racket know what the expression means? This is what an **evaluator** does. An **evaluator** (or **interpreter**) for a programming language is a procedure that, when applied to an expression of the language, performs the @@ -35,20 +33,20 @@ _Wait, what? The evaluator is just a procedure?_ Yes, it is. The evaluator is just another program! -## what is the metacircular evaluator? +## What is the Metacircular Evaluator? ![](http://mitpress.mit.edu/sicp/full-text/sicp/book/chapter-4/figs/eval- apply.gif) -Our evaluator for Lisp will be implemented as a Lisp program. It may seem -circular to think about evaluating Lisp programs using an evaluator that is -itself implemented in Lisp. However, evaluation is a process, so it is -appropriate to describe the evaluation process using Lisp, which, after all, +Our evaluator for Racket will be implemented as a Racket program. It may seem +circular to think about evaluating Racket programs using an evaluator that is +itself implemented in Racket. However, evaluation is a process, so it is +appropriate to describe the evaluation process using Racket, which, after all, is our tool for describing processes. An evaluator that is written in the same language that it evaluates is said to be metacircular. -The metacircular evaluator is essentially a Scheme formulation of the +The metacircular evaluator is essentially a Racket formulation of the environment model of evaluation described in Lesson 8. Recall that the model has two basic parts: @@ -61,8 +59,8 @@ to be applied to arguments, which in turn are reduced to new expressions to be evaluated in new environments, and so on, until we get down to symbols, whose values are looked up in the environment, and to primitive procedures, which are applied directly. This evaluation cycle will be embodied by the interplay -between the two critical procedures in the evaluator, `eval` and `apply`, -which we will go through the details soon. +between the two critical procedures in the evaluator, `eval` and `apply`. We will +go through the details of `eval` and `apply` soon. The implementation of the evaluator will depend upon procedures that define the syntax of the expressions to be evaluated. We will use data abstraction to @@ -77,14 +75,14 @@ that specify the representation of procedures and environments. For example, accesses the values of variables, and `apply-primitive-procedure` applies a primitive procedure to a given list of arguments. -## takeaways +## Takeaways In this subsection, you learned: 1. The definition of evaluator 2. The definition of metacircular evaluator -## what's next? +## What's Next? -Now it's time to understand how Scheme actually works! Exciting! +Now it's time to understand how Racket actually works! Exciting! diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md index 2eeaa39..384e6e0 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md @@ -1,4 +1,9 @@ -## eval +The rest of the lesson has concepts that may be confusing the first time you learn about them, +so carefully reread sentences that are hard to understand! It's also important to remember that +the metacircular evaluator is all about abstraction, so if you don't understand how something +is implemented just yet, it'll probably be explained in a later section. + +## Eval (define (eval-1 exp) @@ -15,52 +20,51 @@ (else (error "bad expr: " exp)))) -Does this code look familar to you? It should, it's part of the Scheme-1 +Does this code look familar to you? It should; it's part of the Racket-1 interpreter you learned in Lesson 6! If you look at line 3, you can see that -`eval-1` is using Scheme's `eval` procedure. You didn't really have to worry +`eval-1` is using Racket's `eval` procedure. You didn't really have to worry too much about the details in Lesson 6, because Scheme's `eval` procedure handled all the details. But then how is `eval` defined? -Now is time to look at how `eval` is written. Take a look, and compare it to +Now is time to look at how `mc-eval` is written. Take a look, and compare it to `eval-1`: - (define (eval exp env) + (define (mc-eval exp env) (cond ((self-evaluating? exp) exp) - ((variable? exp) (lookup-variable-value exp env)) - ((quoted? exp) (text-of-quotation exp)) - ((assignment? exp) (eval-assignment exp env)) - ((definition? exp) (eval-definition exp env)) - ((if? exp) (eval-if exp env)) - ((lambda? exp) - (make-procedure (lambda-parameters exp) - (lambda-body exp) - env)) - ((begin? exp) - (eval-sequence (begin-actions exp) env)) - ((cond? exp) (eval (cond->if exp) env)) - ((application? exp) - (apply (eval (operator exp) env) - (list-of-values (operands exp) env))) - (else - (error "Unknown expression type -- EVAL" exp)))) + ((variable? exp) (lookup-variable-value exp env)) + ((quoted? exp) (text-of-quotation exp)) + ((assignment? exp) (eval-assignment exp env)) + ((definition? exp) (eval-definition exp env)) + ((if? exp) (eval-if exp env)) + ((lambda? exp) + (make-procedure (lambda-parameters exp) + (lambda-body exp) + env)) + ((begin? exp) + (eval-sequence (begin-actions exp) env)) + ((cond? exp) (mc-eval (cond->if exp) env)) + ((application? exp) + (mc-apply (mc-eval (operator exp) env) + (list-of-values (operands exp) env))) + (else + (error "Unknown expression type -- EVAL" exp)))) Don't worry if you don't understand it. We will go through this code step-by- step. -## what does eval do? +## what does mc-eval do? -`Eval` takes as arguments an expression and an environment. It classifies the -expression and directs its evaluation. Eval is structured as a case analysis -of the syntactic type of the expression to be evaluated. In order to keep the +The procedure `mc-eval` takes as arguments an expression and an environment. It classifies the +expression and directs its evaluation. In order to keep the procedure general, we express the determination of the type of an expression abstractly, making no commitment to any particular representation for the various types of expressions. Each type of expression has a predicate that tests for it and an abstract means for selecting its parts. -When `eval` processes a procedure application, it uses `list-of-values` to -produce the list of arguments to which the procedure is to be applied. `List- +When `mc-eval` processes a procedure application, it uses `list-of-values` to +produce the list of arguments to which the procedure is to be applied. The procedure `list- of-values` takes as an argument the operands of the combination. It evaluates each operand and returns a list of the corresponding values: @@ -68,17 +72,19 @@ each operand and returns a list of the corresponding values: (define (list-of-values exps env) (if (no-operands? exps) '() - (cons (eval (first-operand exps) env) - (list-of-values (rest-operands exps) env)))) + (cons (mc-eval (first-operand exps) env) + (list-of-values (rest-operands exps) env)))) +Let's go line by line to see what each expression in the conditional does. + ## PRIMITIVE EXPRESSIONS ![](http://www.bbc.co.uk/music/tinthepark/2010/img/home/radio1_small_promo.jpg ) -For self-evaluating expressions, such as numbers, `eval` returns the -expression itself. `Eval` must look up variables in the environment to find +For self-evaluating expressions, such as numbers, `mc-eval` returns the +expression itself. `mc-eval` must look up variables in the environment to find their values. * The only self-evaluating items are numbers and strings: @@ -103,7 +109,10 @@ world!"`). ![](https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQzrLHmk190OIaf1 -xqLtrpW-BYa-yWwYHL58ZZBqQw6AVbqSZ2qw) - * For quoted expressions, `eval` returns the expression that was quoted. + * For quoted expressions, `mc-eval` returns the expression that was quoted. + +Recall that the Racket parser automatically transforms the expression `'(text of quotation)` into +the expression `(quote text of quotation)`. Quotations have the form `(quote )`: @@ -150,11 +159,13 @@ value`: ![](http://x-equals.com/blog/wp-content/editing_sequences_5_seq_1280.jpg) - * `Eval-sequence` is used by `apply` to evaluate the sequence of expressions in a procedure body. It is also used by `eval` to evaluate the sequence of expressions in a `begin` expression. It takes as arguments a sequence of expressions and an environment, and evaluates the expressions in the order in which they occur. The value returned is the value of the final expression. + * `Eval-sequence` is used by `apply` to evaluate the sequence of expressions in a procedure body. It is also used by `eval` to evaluate the sequence of expressions in a + `begin` expression. It takes as arguments a sequence of expressions and an environment, and evaluates the expressions in the order in which they occur. The value returned + is the value of the final expression. (define (eval-sequence exps env) - (cond ((last-exp? exps) (eval (first-exp exps) env)) - (else (eval (first-exp exps) env) + (cond ((last-exp? exps) (mc-eval (first-exp exps) env)) + (else (mc-eval (first-exp exps) env) (eval-sequence (rest-exps exps) env)))) @@ -181,12 +192,12 @@ a sequence into a single expression, using `begin` if necessary: ![](http://callofcarly.files.wordpress.com/2011/10/if.png) - * `Eval-if` evaluates the predicate part of an if expression in the given environment. If the result is true, eval-if evaluates the consequent, otherwise it evaluates the alternative: + * `Eval-if` evaluates the predicate part of an `if` expression in the given environment. If the result is true, eval-if evaluates the consequent, otherwise it evaluates the alternative: (define (eval-if exp env) - (if (true? (eval (if-predicate exp) env)) - (eval (if-consequent exp) env) - (eval (if-alternative exp) env))) + (if (true? (mc-eval (if-predicate exp) env)) + (mc-eval (if-consequent exp) env) + (mc-eval (if-alternative exp) env))) The use of `true?` in `eval-if` highlights the issue of the connection between @@ -195,7 +206,7 @@ evaluated in the language being implemented and thus yields a value in that language. The interpreter predicate `true?` translates that value into a value that can be tested by the if in the implementation language: The metacircular representation of truth might not be the same as that of the underlying -Scheme. +Racket. `true?` and `false?` are define as following: @@ -218,7 +229,7 @@ Scheme. There is a constructor for `if` expressions, to be used by `cond->if` to -transform cond expressions into `if` expressions: +transform `cond` expressions into `if` expressions: (define (make-if predicate consequent alternative) @@ -290,13 +301,13 @@ to compute the new value to be associated with the variable. The environment must be modified to change (or create) the binding of the variable. The following procedure handles assignments to variables. It calls `eval` to -find the value to be assigned and transmits the variable and the resulting -value to `set-variable-value!` to be installed in the designated environment. +find the value to be assigned and passes the variable and the resulting +value to `set-variable-value!` to be defined in the designated environment. (define (eval-assignment exp env) (set-variable-value! (assignment-variable exp) - (eval (assignment-value exp) env) + (mc-eval (assignment-value exp) env) env) 'ok) @@ -306,7 +317,7 @@ Definitions of variables are handled in a similar manner: (define (eval-definition exp env) (define-variable! (definition-variable exp) - (eval (definition-value exp) env) + (mc-eval (definition-value exp) env) env) 'ok) @@ -354,30 +365,31 @@ The corresponding syntax procedures are the following: (make-lambda (cdadr exp) ; formal parameters (cddr exp)))) ; body -## eval definition revisited +## mc-eval definition revisited -Let's take a look at `eval`'s definition again. Does it make sense to you now? +Let's take a look at `mc-eval`'s definition again. Does it make sense to you now? - (define (eval exp env) + (define (mc-eval exp env) (cond ((self-evaluating? exp) exp) - ((variable? exp) (lookup-variable-value exp env)) - ((quoted? exp) (text-of-quotation exp)) - ((assignment? exp) (eval-assignment exp env)) - ((definition? exp) (eval-definition exp env)) - ((if? exp) (eval-if exp env)) - ((lambda? exp) - (make-procedure (lambda-parameters exp) - (lambda-body exp) - env)) - ((begin? exp) - (eval-sequence (begin-actions exp) env)) - ((cond? exp) (eval (cond->if exp) env)) - ((application? exp) - (apply (eval (operator exp) env) - (list-of-values (operands exp) env))) - (else - (error "Unknown expression type -- EVAL" exp)))) + ((variable? exp) (lookup-variable-value exp env)) + ((quoted? exp) (text-of-quotation exp)) + ((assignment? exp) (eval-assignment exp env)) + ((definition? exp) (eval-definition exp env)) + ((if? exp) (eval-if exp env)) + ((lambda? exp) + (make-procedure (lambda-parameters exp) + (lambda-body exp) + env)) + ((begin? exp) + (eval-sequence (begin-actions exp) env)) + ((cond? exp) (mc-eval (cond->if exp) env)) + ((application? exp) + (mc-apply (mc-eval (operator exp) env) + (list-of-values (operands exp) env))) + (else + (error "Unknown expression type -- EVAL" exp)))) + _Wait, wait, what's apply? I don't know what that is!_ @@ -386,11 +398,11 @@ We are going to explore it in the next subsection. ## takeaways -In this subsection, you learned how Scheme evaluates the expressions using -`eval` and other procedures. +In this subsection, you learned how Racket evaluates the expressions using +`mc-eval` and other procedures. ## What's next? -Go to the next subsection and learn how Scheme applies the evaluated +Go to the next subsection and learn how Racket applies the evaluated expressions! diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md index f156d8a..bfb7e3d 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md @@ -1,34 +1,40 @@ -## apply -`Apply` takes two arguments, a procedure and a list of arguments to which the + +## Apply + +The procedure `apply` takes two arguments: a procedure and a list of arguments to which the procedure should be applied. `Apply` classifies procedures into two kinds: It calls `apply-primitive-procedure` to apply primitives; it applies compound procedures by sequentially evaluating the expressions that make up the body of -the procedure. The environment for the evaluation of the body of a compound -procedure is constructed by extending the base environment carried by the -procedure to include a frame that binds the parameters of the procedure to the -arguments to which the procedure is to be applied. Here is the definition of -`apply`: +the procedure. To create the environment in which we'll evaluate the body of the compound procedure, +we'll extend the base environment of the procedure to include a frame that binds the parameters of +the procedure to the arguments to which the procedure is to be applied. + + Here is the definition of `apply`: - (define (apply procedure arguments) + (define (mc-apply procedure arguments) (cond ((primitive-procedure? procedure) - (apply-primitive-procedure procedure arguments)) + (apply-primitive-procedure procedure arguments)) ((compound-procedure? procedure) - (eval-sequence - (procedure-body procedure) - (extend-environment - (procedure-parameters procedure) - arguments - (procedure-environment procedure)))) + (eval-sequence + (procedure-body procedure) + (extend-environment + (procedure-parameters procedure) + arguments + (procedure-environment procedure)))) (else - (error - "Unknown procedure type -- APPLY" procedure)))) + (error + "Unknown procedure type -- APPLY" procedure)))) We will go through the procedures used in the definition, one-by-one. -## represent procedures +## Represent Procedures + +In our metacircular evaluator, procedures are represented by tagged lists. Primitive +procedures have the tag `primitive`, and compound procedures have the tag `procedure`. If +we want to see what type of a procedure something is, we just have to check its tag. To handle primitives, we assume that we have available the following procedures: @@ -40,6 +46,7 @@ applies the given primitive procedure to the argument values in the list * `(primitive-procedure? proc)` tests whether `proc` is a primitive procedure. + Compound procedures are constructed from parameters, procedure bodies, and environments using the constructor `make-procedure`: @@ -53,17 +60,17 @@ environments using the constructor `make-procedure`: (define (procedure-environment p) (cadddr p)) -## primitive procedures +## Primitive Procedures -At this point, or maybe for a long time, you may wonder how primitive -procedures are represented in Scheme. There is actually no right way to +At this point, you may wonder how primitive +procedures are represented in Racket. There is actually no right way to represent the primitive procedures, as long as `apply` can identify and apply them by using the procedures `primitive-procedure?` and `apply-primitive- procedure`. -People who created Scheme decided to represent a primitive procedure as a list -which begins with the symbol `primitive` and contains a procedure in the -underlying Lisp that implements that primitive. +People who created Racket decided to represent a primitive procedure as a tagged list +that begins with the symbol `primitive` and contains a procedure in the +underlying Racket that implements that primitive. (define (primitive-procedure? proc) @@ -89,7 +96,7 @@ underlying Lisp that implements that primitive. To apply a primitive procedure, we simply apply the implementation procedure -to the arguments, using the underlying Lisp system: +to the arguments, using the underlying Racket system: (define (apply-primitive-procedure proc args) @@ -97,9 +104,9 @@ to the arguments, using the underlying Lisp system: (primitive-implementation proc) args)) -## operations on environments +## Operations on Environments -For sure, the evaluator needs operations for manipulating environments. What +In order to evaluate compound procedures, the evaluator needs operations for manipulating environments. What is an environment again? It is a sequence of frames, where each frame is a table of bindings that associate variables with their corresponding values. We use the following operations for manipulating environments: @@ -132,17 +139,17 @@ empty environment is simply the empty list. (define the-empty-environment '()) -Each frame of an environment is represented as a pair of lists: a list of the +Each frame of an environment is represented as a mutable pair of mutable lists: a list of the variables bound in that frame and a list of the associated values. (define (make-frame variables values) - (cons variables values)) - (define (frame-variables frame) (car frame)) - (define (frame-values frame) (cdr frame)) + (mcons variables values)) + (define (frame-variables frame) (mcar frame)) + (define (frame-values frame) (mcdr frame)) (define (add-binding-to-frame! var val frame) - (set-car! frame (cons var (car frame))) - (set-cdr! frame (cons val (cdr frame)))) + (set-mcar! frame (mcons var (mcar frame))) + (set-mcdr! frame (mcons val (mcdr frame)))) To extend an environment by a new frame that associates variables with values, @@ -150,12 +157,15 @@ we make a frame consisting of the list of variables and the list of values, and we adjoin this to the environment. We signal an error if the number of variables does not match the number of values. - +Notice that since our variables and values must both be mutable lists, we +first have to convert non-mutable lists to their mutable equivalent. (define (extend-environment vars vals base-env) - (if (= (length vars) (length vals)) + (if (not (mlist? vars)) (set! vars (list->mlist vars)) 'ok) + (if (not (mlist? vals)) (set! vals (list->mlist vals)) 'ok) + (if (= (mlength vars) (mlength vals)) (cons (make-frame vars vals) base-env) - (if (< (length vars) (length vals)) + (if (< (mlength vars) (mlength vals)) (error "Too many arguments supplied" vars vals) (error "Too few arguments supplied" vars vals)))) @@ -169,17 +179,17 @@ environment, we signal an "unbound variable" error. (define (lookup-variable-value var env) (define (env-loop env) - (define (scan vars vals) - (cond ((null? vars) - (env-loop (enclosing-environment env))) - ((eq? var (car vars)) - (car vals)) - (else (scan (cdr vars) (cdr vals))))) - (if (eq? env the-empty-environment) - (error "Unbound variable" var) - (let ((frame (first-frame env))) - (scan (frame-variables frame) - (frame-values frame))))) + (define (scan vars vals) + (cond ((null? vars) + (env-loop (enclosing-environment env))) + ((eq? var (mcar vars)) + (mcar vals)) + (else (scan (mcdr vars) (mcdr vals))))) + (if (eq? env the-empty-environment) + (error "Unbound variable" var) + (let ((frame (first-frame env))) + (scan (frame-variables frame) + (frame-values frame))))) (env-loop env)) @@ -190,22 +200,22 @@ value when we find it. (define (set-variable-value! var val env) (define (env-loop env) - (define (scan vars vals) - (cond ((null? vars) - (env-loop (enclosing-environment env))) - ((eq? var (car vars)) - (set-car! vals val)) - (else (scan (cdr vars) (cdr vals))))) - (if (eq? env the-empty-environment) - (error "Unbound variable -- SET!" var) - (let ((frame (first-frame env))) - (scan (frame-variables frame) - (frame-values frame))))) + (define (scan vars vals) + (cond ((null? vars) + (env-loop (enclosing-environment env))) + ((eq? var (mcar vars)) + (set-mcar! vals val)) + (else (scan (mcdr vars) (mcdr vals))))) + (if (eq? env the-empty-environment) + (error "Unbound variable -- SET!" var) + (let ((frame (first-frame env))) + (scan (frame-variables frame) + (frame-values frame))))) (env-loop env)) To define a variable, we search the first frame for a binding for the -variable, and change the binding if it exists (just as in `set-va``riable- +variable, and change the binding if it exists (just as in `set-variable- value!`). If no such binding exists, we adjoin one to the first frame. @@ -213,12 +223,19 @@ value!`). If no such binding exists, we adjoin one to the first frame. (let ((frame (first-frame env))) (define (scan vars vals) (cond ((null? vars) - (add-binding-to-frame! var val frame)) - ((eq? var (car vars)) - (set-car! vals val)) - (else (scan (cdr vars) (cdr vals))))) + (add-binding-to-frame! var val frame)) + ((eq? var (mcar vars)) + (set-mcar! vals val)) + (else (scan (mcdr vars) (mcdr vals))))) (scan (frame-variables frame) - (frame-values frame)))) + (frame-values frame)))) + +**Important:** Notice that when we are defining variables, the value associated +with each variable has already been determined by applying `mc-eval`, so we don't +have to call `mc-eval` again! + +It's also important to notice the distinction between defining variables in the metacircular +evaluator's environment and defining variables in underlying Racket. ## apply revisited diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section04 Running the Evaluator.md b/textbook/chapter22 11 - Metacircular Evaluator/section04 Running the Evaluator.md index a8afe1e..633d264 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section04 Running the Evaluator.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section04 Running the Evaluator.md @@ -1,19 +1,20 @@ -## running the evaluator +## Running the Evaluator -Let's look at how Scheme runs the evaluator. So far, we learned how the Scheme -expressions are evaluated using `eval` and `apply`. Then how is the evaluator +Let's look at how Racket runs the evaluator. So far, we learned how the Racket +expressions are evaluated using `mc-eval` and `mc-apply`. Then how is the evaluator program running? What our evaluator program does is to reduce all the expressions to the application of primitive procedures. So all we need to run the evaluator is -to create a mechanism that uses the underlying Lisp system for the application +to create a mechanism that uses the underlying Racket system for the application of primitive procedures. -There must be a binding for each primitive procedure name, so that when `eval` +There must be a binding for each primitive procedure name, so that when `mc-eval` evaluates the operator of an application of a primitive, it will find an -object to pass to `apply`. We thus set up a global environment that associates +object to pass to `mc-apply`. We thus set up a global environment that associates unique objects with the names of the primitive procedures that can appear in -the expressions we will be evaluating. The global environment also includes +the expressions we will be evaluating (for example, we'll bind `+` to the +underlying Racket procedure with the same name). The global environment also includes bindings for the symbols `true` and `false`, so that they can be used as variables in expressions to be evaluated. @@ -30,7 +31,7 @@ variables in expressions to be evaluated. For convenience in running the metacircular evaluator, we provide a **driver -loop** that models the read-eval-print loop of the underlying Lisp system. It +loop** that models the read-eval-print loop (or REPL) of the underlying Racket system. It prints a **prompt**, reads an input expression, evaluates this expression in the global environment, and prints the result. We precede each printed result by an **output prompt** so as to distinguish the value of the expression from @@ -42,7 +43,7 @@ other output that may be printed. (define (driver-loop) (prompt-for-input input-prompt) (let ((input (read))) - (let ((output (eval input the-global-environment))) + (let ((output (mc-eval input the-global-environment))) (announce-output output-prompt) (user-print output))) (driver-loop)) @@ -86,17 +87,17 @@ environment and start the driver loop. Here is a sample interaction: ;;; M-Eval value: (a b c d e f) -_Wait, I still don't get it. How can we evaluate Scheme code with an evaluator -that is written in Scheme?_ +_Wait, I still don't get it. How can we evaluate Racket code with an evaluator +that is written in Racket?_ -It's because Scheme is powerful enough to handle a program as data, and to let +It's because Racket is powerful enough to handle a program as data, and to let us construct data structures that are both hierarchical and circular. I have an analogy for you in the next section. -## data as programs +## Data as Programs -To understand interpreting Scheme expression with the interpreter written in -Scheme, think of a program as a description of an abstract machine. For +To understand interpreting Racket expression with the interpreter written in +Racket, think of a program as a description of an abstract machine. For example, you can think of the program to compute factorials: @@ -114,7 +115,7 @@ factorial machine within it -- recursion!) So the machine will look like this: Like `factorial`, the evaluator is a very special machine that takes a description of other machine as input, and then configures itself to emulate -the given machine. For example, if we give the evaluator the defintion of +the given machine. For example, if we give the evaluator the definition of `factorial`, the evaluator will emulate it and be able to compute factorials. ![](http://mitpress.mit.edu/sicp/full-text/book/ch4-Z-G-3.gif) @@ -123,11 +124,11 @@ So our evaluator is just a universal machine that mimics all other machines! If you'd like to know more about the machines, ask for Unit 5. -## takeaways +## Takeaways In this subsection, you learned how the evaluator works. -## what's next? +## What's Next? Go do your homework! You should also start on Project 4, where you'll learn the Python programming language. diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section06 Python Interpreter.md b/textbook/chapter22 11 - Metacircular Evaluator/section06 Python Interpreter.md index 29b2082..60882aa 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section06 Python Interpreter.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section06 Python Interpreter.md @@ -1,16 +1,16 @@ ## Introduction to Python We are going to learn about Python, the language that CS61A uses. Your friends -in CS61A are writing a Scheme interpreter in Python. Here in CS61AS, you are -going to write a Python Interpreter written in Scheme for your last project. +in CS61A are writing a Scheme interpreter in Python (Scheme is a language very similar to Racket). +Here in CS61AS, you are going to write a Python Interpreter written in Racket for your last project. ## Opening Python To open Python, go to the terminal and type "python". The ">>>" prompt will -show up which is the equivalent of STk's "STk >". +show up which is the equivalent of Racket's "->". As you will learn, spaces in Python are really important. Spaces for python -are Parentheses for Scheme. +are Parentheses for Racket. ## Playing with Python @@ -27,7 +27,7 @@ How would you ask Python to print "Hello World"? Well, Hello World -and that's it! (Yeah, srsly.) As you may have noticed from that simple +and that's it! (Yeah, seriously). As you may have noticed from that simple example, Python does not need left parentheses to call functions; you do not need to precede 'print' with a left parenthesis. Python is case-sensitive, so "PRINT" would not work. Another key difference is that Python only supports @@ -105,7 +105,7 @@ is overwritten. Python has support for the Boolean operators 'and' and 'or', which work -exactly as the corresponding Scheme special forms work: +exactly as the corresponding Racket special forms work: @@ -160,7 +160,7 @@ Python has lists! (Why wouldn't it?) "x" is now a variable that stores a list of three numbers. As you can guess, -the Scheme analog is "(list 1 2 3)". Python lists can also be deep: +the Racket analog is "(list 1 2 3)". Python lists can also be deep: >>> x = [[1, 2, 3], 2, 3] @@ -205,7 +205,7 @@ infix operator. ### Ifs An important aspect of Python, born of its dedication to readable code, is its -usage of INDENTATION. In most other languages, including Scheme, indentation +usage of INDENTATION. In most other languages, including Racket, indentation is not an issue, since these languages ignore the number of spaces, and instead use spaces to delimit symbols, numbers and words. However, in Python, the number of spaces at the beginning of a line is important. @@ -319,7 +319,7 @@ in Scheme, the left parenthesis can be considered as a prefix operator, which the left parenthesis "calls" its first argument ('square') on the next argument ('3'). Also, if Python procedures need to return values, we have to explicitly add a 'return'-statement to the body to return the answer; by -contrast, in Scheme, the very last line of a procedure definition is always +contrast, in Racket, the very last line of a procedure definition is always returned. This allows us to distinguish between Python functions that return values, and Python functions that do not return values but are used primarily for their side-effects: @@ -365,7 +365,8 @@ the predicate evaluates to False. #### for A "for" loop takes in a list (or any kind of sequence) and runs through the -body with each element of the sequence. +body with each element of the sequence. This is similar to the loops you learned +about in Lesson 9. diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md index 67c2094..24456d1 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md @@ -1,17 +1,17 @@ ## Exercise 1. -List all the procedures in the metacircular evaluator that call `eval`. +List all the procedures in the metacircular evaluator that call `mc-eval`. ## Exercise 2. -List all the procedures in the metacircular evaluator that call `apply`. +List all the procedures in the metacircular evaluator that call `mc-apply`. ## Exercise 3. -Explain why `make-procedure` does not call `eval`. +Explain why `make-procedure` does not call `mc-eval`. ## A Note on Homework 11 @@ -30,11 +30,11 @@ You can copy the template for this homework by typing the following in your terminal: - cp ~cs61as/autograder/templates/hw11.scm . + cp ~cs61as/autograder/templates/hw11.rkt . Or, you can download it -[here](http://inst.eecs.berkeley.edu/~cs61as/templates/hw11.scm). +[here](http://inst.eecs.berkeley.edu/~cs61as/templates/hw11.rkt). ## Exercise 1. From a4c23ef37ac21863da2470a5d8f1a09b63174aea Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Thu, 20 Aug 2015 01:15:00 -0700 Subject: [PATCH 6/9] wanna switch back to master lol --- .../section01 Lesson 11 Intro.md | 6 ++++++ .../section07 Homework 11.md | 5 ++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md b/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md index 56fc01e..0bdab3d 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section01 Lesson 11 Intro.md @@ -3,6 +3,12 @@ Do you remember Racket-1 in Lesson 6? Now it's time to explore how Racket evaluates expressions! +You can download the code for this lesson by typing the following into your terminal: + + cp ~cs61as/lib/mceval.rkt . + +The code is also online [here](http://inst.eecs.berkeley.edu/~cs61as/library/mceval.rkt) + ## Prerequisites and What to Expect A good understanding of how Racket-1 works will be helpful in this chapter. You should diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md index 24456d1..c57a773 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md @@ -15,14 +15,13 @@ Explain why `make-procedure` does not call `mc-eval`. ## A Note on Homework 11 -Some students have complained that this week's homework is very time- -consuming. +Some students have complained that this week's homework is very time-consuming. Accordingly, with some reluctance, we've marked a few exercises as optional; these are the ones to leave out if you're really pressed for time. But it's much better if you do all of them! -The optional ones have * next to them. +The optional exercises have * next to them. ## Template From 5fc532e0686b19ce7c104a3396cb5d9380745af2 Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Thu, 20 Aug 2015 01:43:38 -0700 Subject: [PATCH 7/9] lesson11 all sections proofread and moved to racket --- .../section07 Homework 11.md | 237 ++---------------- 1 file changed, 18 insertions(+), 219 deletions(-) diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md index c57a773..186723b 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section07 Homework 11.md @@ -1,17 +1,9 @@ -## Exercise 1. - - -List all the procedures in the metacircular evaluator that call `mc-eval`. - -## Exercise 2. - - -List all the procedures in the metacircular evaluator that call `mc-apply`. +## Exercise 0. +Some warmup questions to check your understanding: -## Exercise 3. - - -Explain why `make-procedure` does not call `mc-eval`. +- List all the procedures in the metacircular evaluator that call `mc-eval`. +- List all the procedures in the metacircular evaluator that call `mc-apply`. +- Explain why `make-procedure` does not call `mc-eval`. ## A Note on Homework 11 @@ -48,192 +40,11 @@ text/book/book-Z-H-26.html#%_thm_4.11), [4.14](http://mitpress.mit.edu/sicp text/book/book-Z-H-26.html#%_thm_4.15). ## Exercise 4. - Abelson & Sussman, exercises [4.1](http://mitpress.mit.edu/sicp/full- text/book/book-Z-H-26.html#%_thm_4.1), [4.2, 4.4, and 4.5](http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-26.html#%_thm_4.2). -## Exercise 5. - -In this lab exercise you will become familiar with the Logo programming -language, for which you'll be writing an interpreter in project 4. - -To begin, type - -logo - -at the Unix shell prompt - **not** from Scheme! You should see something like -this: - - - Welcome to Berkeley Logo version 5.5 - ? - -The question mark is the Logo prompt, like the > in Scheme. (Later, in some of -the examples below, you'll see a > prompt from Logo, while in the middle of -defining a procedure.) - - * Type each of the following instruction lines and note the results. (A few of them will give error messages.) If you can't make sense of a result, ask for help. - - - print 2 + 3 - - print 2+3 - - print sum 2 3 - - print (sum 2 3 4 5) - - print sum 2 3 4 5 - - 2+3 - - print "yesterday - - print "julia" - - print revolution - - print [blue jay way] - - show [eight days a week] - - show first [golden slumbers] - - print first bf [she loves you] - - pr first first bf [yellow submarine] - - to second :stuff - output first bf :stuff - end - - second "something - - print second "piggies - - pr second [another girl] - - pr first second [carry that weight] - pr second second [i dig a pony] - - to pr2nd :thing - print first bf :thing - end - - pr2nd [the 1 after 909] - - print first pr2nd [hey jude] - - repeat 5 [print [this boy]] - - if 3 = 1+1 [print [the fool on the hill]] - - print ifelse 2=1+1 ~ - [second [your mother should know]] ~ - [first "help] - - print ifelse 3=1+2 ~ - [strawberry fields forever] ~ - [penny lane] - - print ifelse 4=1+2 ~ - ["flying] ~ - [[all you need is love]] - - to greet :person - say [how are you,] - end - - to say :saying - print sentence :saying :person - end - - greet "ringo - - show map "first [paperback writer] - - show map [word first ? last ?] ~ - [lucy in the sky with diamonds] - - to who :sent - foreach [pete roger john keith] "describe - end - - to describe :person - print se :person :sent - end - - who [sells out] - - print :bass - - make "bass "paul - - print :bass - - print bass - - to bass - output [johnny cymbal] - end - - print bass - - print :bass - - print "bass - - to countdown :num - if :num=0 [print "blastoff stop] - print :num - countdown :num-1 - end - - countdown 5 - - to downup :word - print :word - if emptyp bl :word [stop] - downup bl :word - print :word - end - - downup "rain - - ;;;; The following stuff will work - ;;;; only on an X workstation: - - cs - - repeat 4 [forward 100 rt 90] - - cs - - repeat 10 [repeat 5 [fd 150 rt 144] rt 36] - - cs repeat 36 [repeat 4 [fd 100 rt 90] - setpc remainder pencolor+1 8 - rt 10] - - to tree :size - if :size < 3 [stop] - fd :size/2 - lt 30 tree :size*3/4 rt 30 - fd :size/3 - rt 45 tree :size*2/3 lt 45 - fd :size/6 - bk :size - end - - cs pu bk 100 pd ht tree 100 - - - * Devise an example that demonstrates that Logo uses dynamic scope rather than lexical scope. Your example should involve the use of a variable that would have a different value if Logo used lexical scope. Test your code with Berkeley Logo. - - * Explain the differences and similarities among the Logo operators " (double-quote), [ ] (square brackets), and : (colon). - ## Exercise 2*. @@ -246,21 +57,16 @@ predicate function that the argument must satisfy. That function should return `#t` if the argument is valid. For example, here is a procedure foo that has typechecked parameters num and list: -`> (define (foo (integer? num) ((lambda (x) (not (null? x))) lst))` - -` (list-ref lst num))` - -` > (foo 3 '(a b c d e))` - -` d` - -` > (foo 3.5 '(a b c d e))` - -` Error: wrong argument type -- 3.5` - -` > (foo 2 '())` - -` Error: wrong argument type -- () ` +``` +> (define (foo (integer? num) ((lambda (x) (not (null? x))) lst)) + (list-ref lst num)) +> (foo 3 '(a b c d e)) +d +> (foo 3.5 `(a b c d e)) +Error: wrong argument type -- 3.5 +> (foo 2 '()) +Error: wrong argument type -- () +``` In this example we define a procedure `foo` with two formal parameters, named `num` and `list`. When `foo` is invoked, the evaluator will check to see that @@ -269,15 +75,8 @@ not empty. The expression whose value is the desired predicate function should be evaluated with respect to `foo`'s defining environment. (Hint: Think about extend-environment.) -## Extra for Experts +## More Challenge Problems + Here are some more optional exercises if you're interested in this section. These exercises are not for credit. -### Do this if you want to. This is NOT for credit. - -## Exercise 3. - - -Abelson & Sussman, exercises [4.16 - 4.21](http://mitpress.mit.edu/sicp/full- +- Abelson & Sussman, exercises [4.16 - 4.21](http://mitpress.mit.edu/sicp/full- text/book/book-Z-H-26.html#%_thm_4.16). - -# **DO NOT FORGET TO SUBMIT YOUR HOMEWORK!** - From ed030c74826541b7967293e3158da3438b9411ef Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Mon, 24 Aug 2015 15:53:43 -0700 Subject: [PATCH 8/9] additional typo fixes --- .../section02 Eval.md | 14 +++++++------- .../section03 Apply.md | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md index 384e6e0..ee9227f 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md @@ -54,7 +54,7 @@ Now is time to look at how `mc-eval` is written. Take a look, and compare it to Don't worry if you don't understand it. We will go through this code step-by- step. -## what does mc-eval do? +## What Does mc-eval Do? The procedure `mc-eval` takes as arguments an expression and an environment. It classifies the expression and directs its evaluation. In order to keep the @@ -78,7 +78,7 @@ each operand and returns a list of the corresponding values: Let's go line by line to see what each expression in the conditional does. -## PRIMITIVE EXPRESSIONS +## Self-Evaluating Expressions ![](http://www.bbc.co.uk/music/tinthepark/2010/img/home/radio1_small_promo.jpg ) @@ -155,7 +155,7 @@ value`: (cons 'lambda (cons parameters body))) -## special forms: sequences +## Special Forms: Sequences ![](http://x-equals.com/blog/wp-content/editing_sequences_5_seq_1280.jpg) @@ -291,7 +291,7 @@ Expressions (such as `cond`) that we choose to implement as syntactic transformations are called **derived expressions**. `Let` expressions are also derived expressions. -## Special forms: assignments and definitions +## Special Forms: Assignments and Definitions ![](http://2.bp.blogspot.com/-BJ9VKWsOh74/UjWTv9D1TZI/AAAAAAAAfFA/c0x9oTVm2S4/ s1600/DEFINE_TwitterAvatar_R1_eo.png) @@ -365,7 +365,7 @@ The corresponding syntax procedures are the following: (make-lambda (cdadr exp) ; formal parameters (cddr exp)))) ; body -## mc-eval definition revisited +## mc-eval Definition Revisited Let's take a look at `mc-eval`'s definition again. Does it make sense to you now? @@ -396,12 +396,12 @@ _Wait, wait, what's apply? I don't know what that is!_ We are going to explore it in the next subsection. -## takeaways +## Takeaways In this subsection, you learned how Racket evaluates the expressions using `mc-eval` and other procedures. -## What's next? +## What's Next? Go to the next subsection and learn how Racket applies the evaluated expressions! diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md index bfb7e3d..372a0d7 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md @@ -30,7 +30,7 @@ the procedure to the arguments to which the procedure is to be applied. We will go through the procedures used in the definition, one-by-one. -## Represent Procedures +## Representing Procedures In our metacircular evaluator, procedures are represented by tagged lists. Primitive procedures have the tag `primitive`, and compound procedures have the tag `procedure`. If @@ -237,7 +237,7 @@ have to call `mc-eval` again! It's also important to notice the distinction between defining variables in the metacircular evaluator's environment and defining variables in underlying Racket. -## apply revisited +## Apply Revisited Let's look at the definition of `apply` again. Does it make sense this time? @@ -256,7 +256,7 @@ Let's look at the definition of `apply` again. Does it make sense this time? (error "Unknown procedure type -- APPLY" procedure)))) -## takeaways +## Takeaways In this subsection, you learned the following: @@ -264,7 +264,7 @@ In this subsection, you learned the following: 2. How primitive procedures are defined and applied 3. How the operations on environments are defined -## what's next? +## What's Next? We are going to learn how the evaluator runs as a program. From afd7413b376683f170540b9bcc64fe144b735698 Mon Sep 17 00:00:00 2001 From: Alicia Luengo Date: Tue, 25 Aug 2015 18:01:40 -0700 Subject: [PATCH 9/9] added multiple choice questions to lesson 11 --- .../section02 Eval.md | 33 +++++++++++++++++++ .../section03 Apply.md | 10 ++++++ 2 files changed, 43 insertions(+) diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md index ee9227f..80329fb 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section02 Eval.md @@ -75,6 +75,14 @@ each operand and returns a list of the corresponding values: (cons (mc-eval (first-operand exps) env) (list-of-values (rest-operands exps) env)))) +**Left to Right? Right to Left?** +Notice that we cannot tell whether the metacircular evaluator evaluates operands from left to right or from right to left. Its evaluation order is inherited from the underlying Racket: If the arguments to `cons` in `list-of-values` are evaluated from left to right, then `list-of-values` will evaluate operands from left to right; and if the arguments to `cons` are evaluated from right to left, then `list-of-values` will evaluate operands from right to left. + +Write a version of `list-of-values` that evaluates operands from left to right regardless of the order of evaluation in the underlying Racket. Also write a version of `list-of-values` that evaluates operands from right to left. + +
+ +
Let's go line by line to see what each expression in the conditional does. @@ -365,6 +373,20 @@ The corresponding syntax procedures are the following: (make-lambda (cdadr exp) ; formal parameters (cddr exp)))) ; body +**And and Or** + +Recall the definitions of the special forms `and` and `or` from Unit 1: + +* and: The expressions are evaluated from left to right. If any expression evaluates to false, `false` is returned; any remaining expressions are not evaluated. If all the expressions evaluate to true values, the value of the last expression is returned. If there are no expressions then true is returned. + +* or: The expressions are evaluated from left to right. If any expression evaluates to a true value, that value is returned; any remaining expressions are not evaluated. If all expressions evaluate to false, or if there are no expressions, then `false` is returned. + +Install `and` and `or` as new special forms for the evaluator by defining appropriate syntax procedures and evaluation procedures `eval-and` and `eval-or`. Alternatively, show how to implement `and` and `or` as derived expressions. + +
+ +
+ ## mc-eval Definition Revisited Let's take a look at `mc-eval`'s definition again. Does it make sense to you now? @@ -396,6 +418,17 @@ _Wait, wait, what's apply? I don't know what that is!_ We are going to explore it in the next subsection. +
+Which of the following use mc-eval in their definition? Multiple answers may be correct, so check each answer individually. + + + + + + + +
+ ## Takeaways In this subsection, you learned how Racket evaluates the expressions using diff --git a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md index 372a0d7..204a9d3 100755 --- a/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md +++ b/textbook/chapter22 11 - Metacircular Evaluator/section03 Apply.md @@ -256,6 +256,16 @@ Let's look at the definition of `apply` again. Does it make sense this time? (error "Unknown procedure type -- APPLY" procedure)))) +
+Which of the following use mc-apply? Multiple answers may be correct, so check each answer individually. + + + + + + +
+ ## Takeaways In this subsection, you learned the following: