;=====
; CS 111 - Week 5 Lecture 2 - 2025-09-24
;=====

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

;=====
; example involving itemization-style data
;=====

;=====
; say I decided I wanted a function that would
;    "double" values it is "reasonable" to double

;=====
; DATA DEFINITION
; An AddableThing is one of:
;   *   number
;   *   image
;   *   string

;=====
; signature: double-it: AddableThing -> AddableThing
; purpose: expects an addable thing, and:
;    IF it is a number, it returns the result of
;        adding that number to itself
;    ELSE, IF it is an image, it returns the result
;        of creating an image that is two copies of the
;        given image side-by-side,
;    ELSE, IF it is a string, it returns the result
;        of appending the string to itself

; at least 3 tests are needed, in this case

(check-expect (double-it 7)
              14)

(check-expect (double-it (star 65 "solid" "purple"))
              (beside (star 65 "solid" "purple")
                      (star 65 "solid" "purple")))

(check-expect (double-it "seven")
              (string-append "seven" "seven"))

(define (double-it an-addable-thing)
    (cond
        [(number? an-addable-thing) (* 2 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)]
    )
)

(double-it 7)
(double-it (star 65 "solid" "purple"))
(double-it "seven")

(double-it (double-it (star 65 "solid" "purple")))

;=====
; intro to BSL Racket list data type
;=====

;=====
; DATA DEFINITION
; an Anything is an expression of any type

;=====
; DATA DEFINITION
; a list is one of:
;    *   empty
;    *   (cons Anything list)

;-----
; examples of lists

; an empty list -- contains no items

empty

; a list with one item, the string "computer"

(cons "computer" empty)

; a list with two items, the number 4115 and the string "computer"

(cons 4115
      (cons "computer" empty))

; a list with three items, the boolean #false,
;     the number 4115, and the string "computer"

(cons #false
      (cons 4115
           (cons "computer" empty)))

; a list with three items, the strings
;     "tea" and "apple" and "pie"

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

;-----
; "under the hood", this is always how BSL Racket lists
;    are built!
; BUT -- like many languages -- BSL Racket does also
;    provide some features that are just "syntactic sugar",
;    they are just there to make expressing certain things
;    easier

;-----
; list abbreviation is one of these
;
; (list expr1 expr2 ... exprN)
;
; is the SAME as
;
; (cons expr1 (cons expr2 (cons ... (cons exprN empty))...))

(list "tea" "apple" "pie")

(equal? (list "tea" "apple" "pie")
        (cons "tea" (cons "apple" (cons "pie" empty))))

;=====
; some MORE key built-in list operations!

;=====
; DATA DEFINITION
; a NonEmptyList is one of:
;    * (cons Anything empty)
;    * (cons Anything NonEmptyList)

;=====
; signature: cons: Anything list -> list
; purpose: expects any expression and a list,
;   and returns a new list with that expression's value
;   as its first element, and everything else in the given
;   list as the rest of the list

(cons 1 (cons 2 (cons 3 (cons "huh?" empty))))

;=====
; signature: first: NonEmptyList -> Anything
; purpose: expects a non-empty list, and returns the
;     first item in that non-empty list

(first (cons "tea" (cons "apple" (cons "pie" empty))))

(first (list "tea" "apple" "pie"))

(define DRINKS (cons "tea" (cons "coffee" (cons "soda"
                     (cons "water" empty)))))
(first DRINKS)

;=====
; signature: rest: NonEmptyList -> list
; purpose: expects a non-empty list, and returns the list
;    containing everything except the first element of the
;    given list (get it? it returns the REST of the given list)

(rest (cons "tea" (cons "apple" (cons "pie" empty))))

(rest (list "tea" "apple" "pie"))

(rest DRINKS)

(rest (list 1))

;=====
; CONSIDER the BSL Racket list's data definition, again:
;=====
; DATA DEFINITION
; a list is one of:
;    *   empty
;    *   (cons Anything list)
;
; we know, from our experience with itemization style data and enumeration
;     style data, that a function driven by these kinds of data frequently
;     need a cond expression with a branch for each of the possible items
;     in an itemization or each of the possible values in an enumeration;
;
; so: do you see that, for a function driven by a list, you might need
;     a cond with a branch for each of the items in the list's data definition?
;
;     what do you do if a parameter list is empty?
;     what do you do if a parameter list is not empty?

;-----
; SO: Racket provides an easy way to see if you have an empty list!

;=====
; signature: empty?: Anything -> boolean
; purpose: expects any expression with a value, and returns
;     whether it is an empty list

(empty? empty)
(empty? (cons 1 (cons 2 empty)))
(empty? "moo")

(empty? (rest (cons "hi" empty)))

;-----
; also, for convenience, Racket also provides:

;=====
; signature: list?: Anything -> boolean
; purpose: expects any expression with a value, and returns
;     whether it is of data type list

(list? empty)
(list? (cons 1 (cons 2 empty)))
(list? "moo")

(list? (first (cons "hi" empty)))
(list? (rest (cons "hi" empty)))

;=====
; signature: length: list -> number
; purpose: expects any list, and returns the number of
;    (top-level) elements in that list
;
; NOTE: in the list data definition, empty ends a list --
;     it is used to "mark" the end of a list, if you will;
;     the empty ending a list is NOT considered to be an element of
;     that list!

(length empty)
(length (cons "moo" empty))
(length DRINKS)

;-----
; but that's not to say you cannot have a list that has, as one
;    of its elements, an empty list...!

(cons empty empty)
(length (cons empty empty))
(first (cons empty empty))
(rest (cons empty empty))