Please send questions to
st10@humboldt.edu .
(require 2htdp/image)
(require 2htdp/universe)
; CS 131 - Week 5, Lecture 1
; intro to LISTS
; ..because sometimes you want a COLLECTION of things...
; (note: a list is just one of MANY possible kinds of
; collections...)
; here are some examples of a "shopping list" kind of idea
; in the Beginning Student Language of Racket...
empty
(cons "apple" empty)
(cons "tea" (cons "apple" empty))
(cons "HFCS" (cons "banana" (cons "grapes" empty)))
; empty is the empty list (the list of nothing)
;------------
; A data definition for a shopping-list:
; a shopping-list is:
; - empty, or
; - (cons string shopping-list)
; this IS self-referential --
; it is a RECURSIVE definition
; (because shopping-list has been defined in terms of
; shopping-list...)
(cons "rock" (cons "paper" (cons "scissors" empty)))
; you aren't limited to shopping-list -
; there is a GENERAL idea of a list built into Racket
;------------
; data definition for a list:
; a list is:
; - empty, OR
; - (cons anything list)
;------------
; data definition for a non-empty-list:
; a non-empty-list is:
; - (cons anything empty), or
; - (cons anything non-empty-list)
; so, what can you do with a list?
; with those data definitions, I can more
; easily describe the list-related operations
; that this Beginning Student Level of Racket
; provides:
;------------
; signature: cons: anything list -> list
; purpose: expects any expression and a list,
; and it produces a new list with that
; expression as the first list value,
; and everything else in the given list
; becomes the rest of the list...
(cons 1 empty)
(cons "dog" (cons 1 empty))
(cons (place-image (circle 30 "solid" "red") 30 30
(empty-scene 100 100))
(cons "dog" (cons 1 empty)))
;------------
; signature: first: non-empty-list -> anything
; purpose: expects a non-empty list, and produces
; the first item in that list
(first (cons "dog" (cons 1 empty))) ; produces "dog"
(first (cons 1 empty)) ; produces 1
;------------
; signature: empty?: anything -> boolean
; purpose: expects an expression of any type,
; and produces whether it is the empty list
(empty? empty) ; produces true
(empty? (cons 1 empty)) ; produces false
(empty? 1) ; produces false
;------------
; signature: rest: non-empty-list -> list
; purpose: expects a non-empty list, and produces
; a new list of everything BUT the first element
; in that non-empty list
; this produces (cons "dog" (cons false empty))
(rest (cons 1 (cons "dog" (cons false empty))))
; this produces empty (which IS a list, remember)
(rest (cons "fluffy" empty))
(first (cons 3 (cons 17 (cons 8 (cons 2 empty)))))
(rest (cons 4 (cons 5 empty)))
(empty? (rest (cons "fluffy" empty))) ; produces true
; now -- notice that a list data definition is
; a kind of Itemization! (a list is empty, or
; (cons anything list) )
; SO -- like an Itemization,
; a function dealing with a list will often contain
; a conditional expression:
; PART 1 of LIST FUNCTION TEMPLATE IN-PROGRESS
; (cond
; [... ...]
; [... ...]
; )
; 1 branch: when the list is empty
; 1 branch: when it isn't
; step 2 (still not complete) of a template
; for a function uses-list with a list parameter
; a-list
;
; (define (uses-list a-list)
; (cond
; [(empty? a-list) ...]
; [else ...]
; )
; )
; for a struct, the template for a function using
; that struct recognized that you often
; call the selector functions on a struct that
; is a parameter...
; so, for a non-empty list, mightn't you be likely
; to call first and rest on that list?
; step 3 (still not complete) of a template
; for a function uses-list with a list parameter
; a-list
;
; (define (uses-list a-list)
; (cond
; [(empty? a-list) ...]
; [else ...(first a-list) ...
; (rest a-list) ...)]
; )
; )
; AND ...
; consider: we built the list definition in a self-referential
; way;
; a function designed to act on self-refential data
; often will itself also be self-referential,
; or RECURSIVE --
; ...it will call itself! (CAREFULLY!)
; definition: a recursive function is one that calls itself
; (and we'll be discussing how to do so PROPERLY, to
; avoid INFINITE recursion...)
; TWO important means of PROPER recursion:
; there is always at least one NON-recursive case,
; that serve as BASE(s) of the recursion,
; and the recursive call is always on a SMALLER piece
; of the original "thing" (such that, if you keep
; recursing, a base case must eventually be reached...)
; step 4 (now complete!) of a template
; for a function uses-list with a list parameter
; a-list
;------------
; template for a function uses-list that has a list
; parameter a-list
;
; (define (uses-list ... a-list ...)
; (cond
; [(empty? a-list) ...]
; [else (...(first a-list) ...
; (uses-list ... (rest a-list) ...) ...)]
; )
; )
; a first list function!
;------------
; here's a function that takes a list, and produces its
; length (the number of top-level elements in the list)
; signature: len: list -> number
; purpose: expects a list, and produces the number of
; top-level elements in the list
; better have at least 2 check-expects -- one for the
; empty list case, and one for the non-empty-list
; case!
(check-expect (len empty) 0)
(check-expect (len (cons 1 (cons "dog" (cons true empty))))
3)
; (define (len a-list)
; ...
; )
; AFTER the check-expects -- you can now paste in the
; template for a function that expects a list parameter
; (define (len a-list)
; (cond
; [(empty? a-list) ...]
; [else (...(first a-list) ...
; (uses-list ... (rest a-list) ...) ...)]
; )
; )
; ...and remember to change the generic uses-list function
; name in the recursive call to THIS function's name, len!
; (define (len a-list)
; (cond
; [(empty? a-list) ...]
; [else (...(first a-list) ...
; (len ... (rest a-list) ...) ...)]
; )
; )
; from the check-expects -- what is the value of the len
; function when called with the empty list? 0, for 0
; elements;
; (define (len a-list)
; (cond
; [(empty? a-list) 0]
; [else (...(first a-list) ...
; (len ... (rest a-list) ...) ...)]
; )
; )
; ...and since len only has 1 parameter, can remove the extra
; ...'s in the recursive call...
; (define (len a-list)
; (cond
; [(empty? a-list) 0]
; [else (...(first a-list) ...
; (len (rest a-list)) ...)]
; )
; )
; now -- if this works -- what is (len (rest a-list))?
; ...isn't it the length of the rest of the list a-list?
; so don't I want to add 1 to (len (rest a-list)) to get
; a-list's length? (and I just don't need (first a-list),
; for this particular function...)
(define (len a-list)
(cond
[(empty? a-list) 0]
[else (+ 1
(len (rest a-list)))]
)
)
(len (cons 1 (cons 23 (cons 15 (cons 4 empty)))))