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