|
And they're off. Alyssa P. Hacker pulls into an early lead but Ben Bit Diddle is just an instruction or two behind. They are now approaching the first branch and in a surprise move Ben has forked! He's forked! This is a bold move to make so early in the race, and if he isn't careful he could starve himself. But it looks like Ben's move is paying off, he's taken both branches of the conditional and has passed Alyssa who had to backtrack on account of a faulty prediction.They're car and cdr through the middle section of the course which is very tricky this year. Whoooaaaa! Alyssa has pulled her patented cadddadr. We've been wondering if she would pull that one out tonight. Our scouts reported that she's been working on incorporating it into a helper function in her training, but the obscurity of the cadddadr has allowed her to sneak past Ben who is still only up to a cdadr. Alyssa is ahead by 3-4 instructions after her amazing execution of that move. As they come into the finalizer, Garbage C. Lector has just been let loose and is right on Ben's cdr. He better watch out. Ben's taking evasive maneuvers and has forked again. Lector, confused by this turn of events is now going after Alyssa but she's almost terminated. Oh my! Oh my! Look at that, oh right you can't, I forgot this is radio. Anyway, Ben has just pulled a move that hasn't been done since 1979 by Apple B. Sic, he has done an unconditional jump and beaten Alyssa by one instruction! This is incredible. The drives are spinning in their trays and the power supply fans are going wild. This is a race to go into the record books. Well thanks for tuning in and now a word from our sponsors.... --- by special correspondent, Michael Oltmans, MIT CSAIL, 2005 |
An interesting property of Scheme is that there is really only one data structure: LISTS, and we will get very familiar with this during the course of this lecture. Which is important because you will build other data structures using this: trees, tables, matrices, graphs, polynomials, webpages - you name it.
But the first thing we need to know about is pairs:
There are four main operations for Pairs
> (define a (cons 2 3)) > a (2 . 3) > (car a) 2 > (cdr a) 3 > (pair? a) #t
One can think of the value of a pair as being a box with two parts. Pairs are also referred to as cons cells.
(cons 2 3)
-----------
| | |
| 2 | 3 |
-----------
We can use pairs to create more complex things. What structure does this produce?
> (define foo
(cons (cons (cons 1 2) (cons 3 4)) (cons (cons 5 6) (cons 7 8))))
Notice that this implies that we can put things other than numbers inside pairs - including other pairs! And the two halves of the pair do not need to contain the same kind of data. Thus we can use pairs to make all kinds of complex structures, like binary trees.
But we also need to be able to get data back out of our pair structures (i.e. how do we access an element). For example, how do I get the number "2" back out from foo?
>(cdr (car (car foo))) 2
X is a list if
The empty list is a special object of its own type. It is not a pair, it has no elements and its length is zero. One can check if X is an empty list by either (null? X) or (equal? X '())
We can understand lists in a bottom up way, by building some simple lists and drawing their box diagrams.
EMPTY LIST '() LIST WITH ONE ELEMENT (cons 1 '()) LIST WITH 3 ELEMENTS (cons 3 (cons 2 (cons 1 '() )))
We can write a simple function called number-list that takes a positive number n and returns a list of numbers in descending order.
(define (number-list n)
(if (<= n 0)
'()
(cons n (number-list (- n 1)))))
> (number-list 0)
> (number-list 5)
Note that this is just another recursive procedure, like the ones we seen before. And "cons" in this context is more like "add-to-the-front".
Accessing Elements of a List
Since a list is just made up of pairs, we can use car and cdr to access pieces of it. In the context of a list, "car" means "first element" and "cdr" means "rest-of-the-list".
> (define fivelist (number-list 5)) (5 4 3 2 1) > (car fivelist) 5 > (cdr fivelist) (4 3 2 1) > (car (cdr fivelist)) 4
More Functions on Lists
Scheme provides several functions for manipulating lists, the most important of which are null?, list?, list, length, member. But we can actually write many of these functions just by using the pair abstraction.
(define mytestcase (list 1 2 3 4 5 6))
;; LENGTH
;;---------
(define (mylength lst)
(if (null? lst)
0
(+ 1 (length (cdr lst)))))
;; LIST?
;;-------
(define (mylist? whatami)
(if (null? whatami) ; check if equal to '()
#t
(if (pair? whatami)
(mylist? (cdr whatami))
#f)))
Instead of nested ifs, it is better to use a cond statement (will see this again in section). The format of cond is as shown below, and the predicates are looked at in the order written.
(cond (predicate1 then-expression1)
(predicate2 then-expression2)
....
(else else-expression))
Now we can rewrite mylist? as
(define (mylist? whatami) (cond ((null? whatami) #t) ((pair? whatami) (mylist? (cdr whatami))) (else #f)))
This is much easier to read (especially if indented properly). Note that this mirrors our recursive definition of lists very well.
What are good TEST CASES for this function?
What would happen if I switched the order of the first two statements in the cond?
;; MEMBER ;;-------- ;; Mymember (like the real member function in Scheme) ;; looks for an element in the list, and if it finds it then ;; it returns the remaining list starting with that element. ;; if it doesn't fnd it, it returns #f (define (mymember element lst) (cond ((null? lst) #f) ; didn't find it ((equal? (car lst) element) lst) (else (mymember element (cdr lst))) ))
What are good TEST CASES for this function?
Lists can be useful for manipulating data other than numbers, especially for manipulating "symbols" because symbols can represent many of things. Consider a webpage, like last week's notes
<html> <body> <font face="Arial"> <h1>CS 51 Week 1, L1: <i>The Best Laid Scheme</i> </h1> <hr> <b>Today's topics:</b> <uL> <li> Abstraction and Design <li> Introduction to Scheme <ul> <li> History <li> Parts of the Language (primitives, combination, abstraction) <li> The Interpreter's point of view <li> Special Forms <li> Recursion </ul> <br> <li><i>Reading: SICP 1.1</i> </ul> .... |
Its really a bunch of symbols, some of which are text and some of
which are tags defined by HTML that are used by your browser to decide
how to display the page.
Suppose I could take a file and read it into a list of symbols**
In fact Scheme does provide such a function called
"read", which you can look up the R5RS Scheme Reference
(define mywebpage (list '<html> 'This 'is 'the 'CS '51 'webpage
'and 'thats 'all 'there 'is 'to 'it '</html> ))
Scheme provides a a short hand (syntactic sugar) for writing
this. (syntactic sugar means that scheme literally replaces your text
with text of the other form above, before evaluating it)
(define mywebpage '(<html> This is the CS 51 webpage and
thats all there is to it </html>))
Note that all the list manipulating functions from before do not care what we have in the lists, so they also work for lists of symbols.
;; is this page about CS? (member 'CS mywebpage) ;; is this page about CS 51? (equal? '51 (car (cdr (member 'CS mywebpage)))) ;; is there an email address on this page? (member '@ mywebpage)
What about more complicated queries, for example
If we "think" of a webpage as a list, then the operations that a search engine or webcrawler might perform can be thought of as simply list accessing functions. Similarly, we can use list manipulation to manipulate our webpages.
Find and Replace
Lets write a useful function that edits a page by replacing a given word by a new word. Maybe to change the look and feel of a webpage.
(find-and-replace 'Arial 'Helvetica) <---change webpage look and feel (find-and-replace 'grey 'violet) (define (find-and-replace aword newword mypage) (cond ((null? mypage) _____ ) ((not (pair? mypage)) _________) ((equal? (car mypage) aword) ( _________________________________ )) (else (__________________________________ ))) ))
(define cs51 51)
A Scheme program is just a ........ LIST OF SYMBOLS!
And the Interpreter is just a ..... PROGRAM THAT MANIPULATES LIST!
> (define mycode (list 'define 'cs51 '51)) > mycode (define cs51 51) > (car mycode) define > cs51 reference to undefined identifier: cs51 > (eval mycode) ;; <----explicitly calling the interpreter (evaluator) > cs51 51
Scheme is dialect of LISP. The name LISP derives from "LISt Processing". Linked lists are Lisp's main data structure and the same basic operations work in all lisp dialects. |
Lisp was created to explore AI - the idea that a machine could be intelligent. But what is intelligence? Well one of the things humans are incredibley good at is creating, using, and manipulating symbols. We do mathematics and reason about variables that abstractly represent something possibly physical; we can attach names to something as complex as an emotion and then write whole books analyzing this emotion and its consequences for human culture, we play chess or sudoku. In short, maybe symbol manipulation is intelligence?
Many of the earliest programs in LISP explored powerful symbol
manipulation ideas -- mathematical (symbolic math), chess players
(game playing), natural language understanding (like ELIZA).
Perhaps the most important consequence of computational thinking will be in the development of an understanding of ourselves as computational beings. |
So far we have looked at lists of numbers and symbols, but actually we can make lists of anything - including lists of pairs and lists of lists.
For example,
(define my-triangle (list (cons 0 0) (cons 1 2) (cons 3 4)))
(define my-tflist (list
(list 'Jean 'Yang (list 'section '4:00 'officehrs '8))
...))
(define mymatrix (('row 1 2 3 4 5) ('row 3 4 5 6 7) ('row 5 6 7 8 9)))
And we can draw these lists in very much the same way as before:
(define mycomplexlst (list (list 1 2 3 4) (list 5 6)))
BOX DIAGRAM:
How do our old functions behave when applied to mycomplexlst?
> (list? mycomplexlst) > (length mycomplexlst) > (member '5 mycomplexlst)Notice that all these functions still work, but all they care about is that mycomplexlst has the right "high-level" structure. They do not care at all what we put in the "car" sections of the boxes.
;; The length of a simple list
(define (mylength lst)
(cond ((null? lst) 0)
((not (pair? lst)) 'error-input-not-alist)
(else (+ 1 (length (cdr lst))))))
;; The length of a list in terms of "atoms"
(define (count-atoms slist)
(cond ((null? slist) 0)
((not (pair? slist)) 1)
(else (+ (count-atoms (car slist))
(count-atoms (cdr slist))))))
> (mylength mycomplexlst)
2
> (count-atoms mycomplexlst)
6