|
;; Conditionals |
|
|
|
(require 2htdp/image) |
|
(require cs111/iterated) |
|
|
|
;; boolean is one of |
|
;; - true (#true, #t) |
|
;; - false (#false, #f) |
|
|
|
;; and : boolean, boolean, ... -> boolean |
|
;; returns true if and only if all inputs are true |
|
(check-expect (and #t #t) #t) |
|
(check-expect (and #f #t) #f) |
|
|
|
;; or : boolean, boolean, ... -> boolean |
|
;; returns true if at least one input is true |
|
(check-expect (or #f #t) #t) |
|
(check-expect (or #f #f) #f) |
|
|
|
;; not : boolean -> boolean |
|
(check-expect (not #t) false) |
|
(check-expect (not #false) #t) |
|
|
|
;; Conditionals vs. functions: conditionals will "skip" branches |
|
|
|
;; `or` only requires one argument to be true |
|
(or (> 5 3) ; this is true |
|
(string=? "happy" "birthday")) ; so we never evaluate this |
|
|
|
;; Consider this (nonsensical) case, where we skip an expensive computation |
|
;; because we don't need to know the answer |
|
(or (> 5 3) |
|
;; the next line never gets called |
|
(iterated-overlay (lambda (n) (circle n "solid" "red")) |
|
100000000000000000000)) |
|
|
|
;; Technically this should throw an error because `iterated-overlay` |
|
;; returns an image, and `or` takes booleans only |
|
;; But we never throw the error if we never run the problematic code |
|
|
|
;; Alternatively, suppose the first condition is #false, then we |
|
;; have to check the next one to see if it's true... |
|
;; This time we DO throw the error |
|
; (or (= 5 3) ; 5 =/= 3, so this is #false |
|
; (iterated-overlay (lambda (n) (circle n "solid" "red")) |
|
; 100000000000000000000)) |
|
; ;; now we DO call the next line... |
|
|
|
|
|
;; if : boolean, X, Y -> X or Y |
|
; (if <Predicate> ; "predicate" = "boolean, or expression that simplifies to a boolean" |
|
; <TrueCase> |
|
; <FalseCase>) |
|
|
|
|
|
;; If <Predicate> is true, we |
|
;; skip the <FalseCase> branch entirely |
|
(if (> 2 1) |
|
"it was true" |
|
(5)) ; this should throw an error (why?), but we never run it |
|
|
|
;; checks-value : any -> string |
|
(define (checks-value x) |
|
(if (string? x) |
|
(if (string=? "hello") |
|
"it was a string that was hello" |
|
"it was a string that wasn't hello") |
|
(if (number? x) |
|
(if (= x 2) |
|
"it was 2" |
|
"it was a number that wasn't 2") |
|
"it was not a string or number"))) |
|
|
|
;; Notice we are COMPOSING `if` statements here |
|
; (if <Predicate> |
|
; <TrueCase> ; this can be another `if` statement |
|
; <FalseCase> ; this can also be another `if` statement |
|
|
|
|
|
;; USE THE STEPPER ON SOME EXAMPLES |
|
;; IT'S CONFUSING TO JUST TRY TO READ IT |
|
|
|
; (cond |
|
; [<Predicate> <ReturnValue>] |
|
; [<Predicate> <ReturnValue>] |
|
; [<Predicate> <ReturnValue>] |
|
; ... |
|
; [else <Catch-AllValue>]) |
|
|
|
|
|
;; Some stuff is really annoying to write with `if` |
|
; ;; check-type : any -> string |
|
; (define check-type |
|
; (lambda (x) |
|
; (if (string? x) |
|
; "string" |
|
; ;; Notice we're nesting another `if` in the `else` case |
|
; (if (number? x) |
|
; "number" |
|
; (if (boolean? x) |
|
; "boolean" |
|
; (if (image? x) |
|
; "image" |
|
; ; ... this could go on forever... |
|
; ; ... |
|
; "type unrecognized")))))) |
|
|
|
|
|
;; How about using `cond`? |
|
|
|
;; check-type : any -> string |
|
(define check-type |
|
(lambda (x) |
|
(cond |
|
[(string? x) "string"] |
|
[(number? x) "number"] |
|
[(boolean? x) "boolean"] |
|
[(image? x) "image"] |
|
;; ... |
|
[else "type unrecognized"]))) |