; CS 111 - Week 5 Lecture 2 - 2016-09-22

(require 2htdp/image)
(require 2htdp/universe)

; one more itemization example:

; say I want a function that can accept
;    a string or number or image,
;    and "double it" in a way appropriate
;    to that type...

; DATA DEFINITION
; an AddableType is one of:
; *   number
; *   image
; *   string

; signature: double-it: AddableType -> AddableType
; purpose: expects an addable type of thing,
;     a number, image, or string,
;     and if it is a number, return the result
;         of adding that number to itself,
;     and if it is an image, returns the image
;         you get by putting that image beside
;         itself,
;     and if it is a string, returns the string
;         resulting from appending that string
;         to itself
;     (and it will give an ERROR otherwise...)

;(define (double-it an-addable-thing)
;  ...
;)

(check-expect (double-it 4) 8)
(check-expect (double-it (circle 40 "solid" "green"))
              (beside (circle 40 "solid" "green")
                      (circle 40 "solid" "green")))
(check-expect (double-it "yo")
              "yoyo")
(check-error (double-it #true)
             "argument must be an AddableType")

; for this itemization, 4 branches seems
;    appropriate for the cond-template
;    (1 for each possible item in the
;    itemization, and 1 more for bad data)

;(define (double-it an-addable-thing)
;    (cond
;        [... ...]
;        [... ...]
;        [... ...]
;        [... ...]
;    )
;)

(define (double-it an-addable-thing)
    (cond
        [(number? an-addable-thing)
             (+ an-addable-thing an-addable-thing)]
        [(image? an-addable-thing)
             (beside an-addable-thing
                     an-addable-thing)]
        [(string? an-addable-thing)
             (string-append an-addable-thing
                            an-addable-thing)]
        [else
             (error
                  "argument must be an AddableType")]
    )
)

(double-it 4)
(double-it (circle 40 "solid" "green"))
(double-it "yo")

;===============
; LISTS!!!

; everything up to now has been
;    a single value --
; what if a thing could be a COLLECTION
;    of values?
; ...a collection can be called a data
;    structure,
; and the BSL Racket list type
;    is going to be our first data structure

; we'll START with a ShoppingList concept,
;    (and then generalize to a list...)

; here are EXAMPLES of a Racket ShoppingList

; say these are shopping lists in Racket

; the shopping list with one apple

(cons "apple" empty)

; the shopping list with tea and an apple

(cons "tea"
      (cons "apple" empty)) 

; the shopping list with chocolate and tea and
;    an apple

(cons "chocolate"
      (cons "tea"
            (cons "apple" empty)))

; by the way, the SHORTEST shopping list is
;    the empty shopping list -- you can
;    say this with:

empty

; ack, 6.6 also lets you say

'()

; let's try to build a data definition for
;    a ShoppingList

; DATA DEFINITION
; a ShoppingList is:
; *   empty
; *   (cons string ShoppingList)

; define a ShoppingList USING a ShoppingList?!
; YES, IF we are careful!

; a SELF-REFERENTIAL data definition CAN be
; OK!!!! IF:
; *   there MUST be at least one item in
;     the itemization that ISN'T self-referential
; *   and, the other items should "build"
;     appropriately from the non-self-referential
;     items

; a self-referential definition is also
;    called a RECURSIVE definition

; in BSL Racket,
; the list type can be defined as:
; DATA DEFINITION:
; a list is one of:
; *   empty
; *   (cons anything list)

; like any built-in data type,
; there are provided operations for BSL Racket
; lists:

; signature: cons: anything list -> list
; purpose: expects any expression (that has a value)
;    and a list, and it returns the new list
;    consisting of the value of that 1st
;    expression followed by everything in
;    the given list

(cons "juice" (cons 4
   (cons (radial-star 45 67 23 "solid" "aqua")
       (cons "skrt" empty))))

(define EXAMPLE-LIST
  (cons "juice" (cons 4
     (cons (radial-star 45 67 23 "solid" "aqua")
        (cons "skrt" empty)))))
                                         
; DATA DEFINITION:
; a NonEmptyList is one of:
; * (cons anything empty)
; * (cons anything NonEmptyList)

; signature: first: NonEmptyList -> anything
; purpose: expects a non-empty list,
;    and returns the first thing in that list

(first EXAMPLE-LIST)

; signature: rest: NonEmptyList -> list
; purpose: expects a non-empty list, and
;     returns a new list consisting of
;     all BUT the first element in the
;     given list

(rest EXAMPLE-LIST)

; first returns a list element,
; rest always returns a list!!

(rest (cons 4 (cons 5 empty)))
(rest (cons 5 empty))

; do you need to sometimes see if a list is
;    empty? Definitely!

; signature: empty?: anything -> boolean
; purpose: expects any expression (with a value)
;    and returns whether or not it is an
;    empty list
;    (returns #true if it is an empty list,
;    and returns #false otherwise)

(empty? empty)
(empty? "george")
(empty? EXAMPLE-LIST)
(empty? 4)