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