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

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

;=====
; ASIDE: you can "throw" your own errors in BSL Racket!
;
; function error expects a string argument error message,
;     and has the SIDE-EFFECTS of causing an error to occur
;     and printing the given string argument as the error message
;     to the screen
;
; function check-error lets you write a test to see if a function
;     using the error function causes an error when it should!
; check-error's first argument is the expression to test,
;     and its second is the string error message printed if
;     that error occurs
;
; We'll USE this in our implementation of double-it, below!

;=====
; FINISHING function double-it, that we started
;     on 2026-09-22

;=====
; once upon a time, a CS 111 student asked if you
;     could write a function that, say, behaved one
;     way if given an image, and another way if given
;     a number, etc. -- that inspired this example:

;=====
; 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 two times that number,
;    *   if it is an image, it returns that image side-by-side,
;    *   if it is a string, it returns that string appended to
;        itself
;    (and it should give an error otherwise)

(check-expect (double-it 3) 6)

(check-expect (double-it (circle 20 "solid" "red"))
              (beside (circle 20 "solid" "red")
                      (circle 20 "solid" "red")))

(check-expect (double-it "moo") "moomoo")

; IF I am using the error function to "throw" an error,
;     I can (and should) use check-error to TEST if that
;     error occurs when it should!

(check-error (double-it #false)
             "double-it: argument must be an AddableThing")

(define (double-it an-addable-thing)
    (cond
        [(number? an-addable-thing)
             (* an-addable-thing 2)]
        
        [(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 "double-it: argument must be an AddableThing")]
    )
)

(double-it 3)
(double-it (circle 20 "solid" "red"))
(double-it "moo")

(double-it (text (double-it (number->string (double-it 13)))
                 30 "red"))

; uncomment this to see the error that occurs
;
;(double-it #false)

;=====
; 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 "apple"

(cons 13 (cons "apple" 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 - a shortcut function named list -- is
;    an example of such "syntactic sugar":
;
; (list expr1 expr2 ... exprN)
;
; is the SAME as
;
; (cons expr1 (cons expr2 (cons ... (cons exprN empty))...))

(list 13 "apple")

(equal? (list 13 "apple")
        (cons 13 (cons "apple" empty)))

(list 1 2 3 4 5 6 7 8 9 10 11 12 13 14)

(equal?
    (list 1 2 3 4 5 6 7 8 9 10 11 12 13 14)
    (cons 1 (cons 2 (cons 3 (cons 4 (cons 5
         (cons 6 (cons 7 (cons 8 (cons 9 (cons 10
             (cons 11 (cons 12 (cons 13 (cons 14 empty))))))))))))))
)

;=====
; some basic built-in list operations!
;
; (because when you provide a data type, you need
;     to provide basic operations for instances of that
;     data type! how to create them, how to muck with them,
;     etc.!)

;=====
; 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
;    that list's first element

(first (cons 13 (cons "apple" empty)))

(equal? (first (cons 13 (cons "apple" empty)))
        13)

;=====
; signature: rest: NonEmptyList -> list
; purpose: expects a non-empty list, and returns a new
;     list that is everything from the given list EXCEPT
;     its first item
; (get it? it returns the REST of the given list)

(rest (cons 13 (cons "apple" empty)))

(equal? (rest (cons 13 (cons "apple" empty)))
        (cons "apple" empty))

(rest (list 1 2 3 4 5))

(equal? (rest (list 1 2 3 4 5))
        (cons 2 (cons 3 (cons 4 (cons 5 empty)))))

;=====
; DEMONSTRATING correct answers for Problems 1-4 of the
;     in-class paper activity

(equal?
    (first (cons 3 (cons 17 (cons 8 (cons 2 empty)))))
    3)

(equal?
    (first (list "a" "b" "c" "d"))
    "a")

(equal?
     (rest (cons 4 (cons 5 empty)))
     (cons 5 empty))

(equal?
     (rest (list 7))
     empty)

;=====
; 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")

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

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

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

;=====
; signature: length: list -> number
; purpose: expects any list, and returns the number
;    of (top-level) items in the 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 (list 2 4 6 8 10))

;=====
; DEMONSTRATING correct answers for Problems 5-11 of the
;     in-class paper activity

(equal? (first (rest (rest (list 2 4 6 8 10))))
        6)

(equal? (rest (rest (rest (list 2 4 6 8 10))))
        (cons 8 (cons 10 empty)))

(equal? (empty? (rest (cons #true empty)))
        #true)

(equal? (empty? 17)
        #false)

(equal? (list? (rest (list 438)))
        #true)

(equal? (length (cons #true (cons 13 (cons "ha" empty))))
        3)

(equal? (length empty)
        0)