Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ 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
procedure, `assoc,` which will play a huge role. `assoc` accepts a `key` and a
Before we dive right into tables, we have to explore another Racket compound
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.
Expand All @@ -33,61 +31,77 @@ 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
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
.tg .tg-e3zv{font-weight:bold}
</style>
<table class="tg">
<tr>
<th class="tg-e3zv">Keys</th>
<th class="tg-e3zv">Values</th>
</tr>
<tr>
<td class="tg-031e">a</td>
<td class="tg-031e">1</td>
</tr>
<tr>
<td class="tg-031e">b</td>
<td class="tg-031e">2</td>
</tr>
<tr>
<td class="tg-031e">c</td>
<td class="tg-031e">3</td>
</tr>
</table>

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

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



(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
Expand All @@ -100,22 +114,24 @@ 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)
(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

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:
Expand All @@ -132,6 +148,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
Expand All @@ -141,11 +162,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)))

Expand All @@ -154,25 +175,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
Expand All @@ -182,41 +203,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
Expand All @@ -229,15 +254,17 @@ under 2 keys using the procedures `get` and `put`.
(get <key-1> <key-2>)


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`.

Loading