;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-beginner-reader.ss" "lang")((modname union-type-intro) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) #| ; What is the type of: symbol=? ; of: symbol? symbol=? : symbol symbol -> boolean (-> symbol? symbol? boolean?) symbol? : any -> boolean (-> any/c boolean) Quiz: What are the steps of the design recipe? Take 1, when dealing with primitive types: ---- per function: 4. write tests 5. stub: signature, purpose-statement, header, stub 7. complete the function-body 8. watch your tests pass |# #| TASK: Data definition: a "username" is: a string of one or more lowercase roman letters (possibly followed by digits), whose length is in [1,14) Give some examples of this data-type. "ibarland" "mflatt73" "x" "abcdefghijklm" "a234567890123" Optional [we'll skip it]: Write `username?` [hint: we'll use regexp, as a bit of hack, since we haven't discussed loops] Data definition: A "lookup-result" is one of: - a username, OR - #false (indicating no entry), OR - 'private (indicating entry exists, but information is non-public). Let's give several examples of this type of data: #false 'private "ibarland" Write a function which, given a lookup-result, returns a string: either - a radford email address (e.g. “ibarland@radford.edu”), OR - “No such person.”, OR - “Information not published.”. |# (check-expect (lookup-result->string #false) "No such person.") (check-expect (lookup-result->string 'private) "Information not published.") (check-expect (lookup-result->string "ibarland") "ibarland@radford.edu") ; lookup-result->string : lookup-result -> string ; Return a end-user-friendly string representation of ... (define (lookup-result->string a-lr) (cond [(string? a-lr) (string-append a-lr "@radford.edu")] [(false? a-lr) "No such person."] [(symbol? a-lr) "Information not published."])) #| Now let's write a function which takes in a lookup-result, just returns whether this is a known student. |# (check-expect (known-student? "ibalrand") #true) (check-expect (known-student? #false) #false) (check-expect (known-student? 'private) #true) ; known-student? : lookup-result -> boolean ; returns whether this is a known student. ; (define (known-student? a-lr) (cond [(string? a-lr) #true] [(false? a-lr) #false] [(symbol? a-lr) #true])) #| Now, let's write a function which takes in a lookup-result, and ...[???]... |# ; func-for-lookup-result : lookup-result -> ??? ; (define (func-for-lookup-result a-lr) (cond [(string? a-lr) ...] [(false? a-lr) ...] [(symbol? a-lr) ...])) ; we will call the above the TEMPLATE for lookup-results. #| We actually just did several more steps of the design-recipe. 1. Make appropriate data definition (if needed). 2. Give some examples of that type of data 3. Template: a. If handling a union type, include a cond w/ one branch per option. ------- per function: 4. tests 5. stub : signature, header, purpose-statement, stub-body (copying template, if any) 7. complete the body-expression 8. watch your tests pass Note that if we write five more functions involving stoplight-colors, we only need do steps 1-3 once. (And we'll copy/paste 3a over and over, for each functions.) |# #| Another example of a natural union-type: A file is: - a string (interpretation: filename) - a file-descriptor (interpretation: the already-opened file) [ It's a pain to have functions that want to open a file and work with it, and then call a helper-function which requires the filename ...] Another type of a natural union-type: - a number, - a pair of numbers (an interval -- min and max) - a list-of-intervals - an indicator function E.g. an auto-grader for hw counts #occurs of "cond" (or of "["), and might want exactly 3, or between 2 and 5, or iether 2-5 or 7-9, or a multiple-of-3 |# ; Task: `turn`, for changing a stop-light. ; ...wait, what data type to use? ; Data Definition: ; A slc ("stoplight color") is one of: ; - 'red, OR ; - 'yellow, OR ; - 'green, OR ; - 'flashing-yellow, OR ; - 'flashing-red ;Examples of the data (duh): 'red 'yellow 'green 'flashing-yellow 'flashing-red (check-expect (turn 'red) 'green) (check-expect (turn 'green) 'yellow) (check-expect (turn 'yellow) 'red) (check-expect (turn 'flashing-red) 'flashing-red) (check-expect (turn 'flashing-yellow) 'flashing-yellow) ; turn : slc -> slc ; return the next color for a stop-light. ; (define (turn curr-color) (cond [(symbol=? curr-color 'red) 'green] [(symbol=? curr-color 'yellow) 'red] [(symbol=? curr-color 'green) 'yellow] [(symbol=? curr-color 'flashing-yellow) 'flashing-yellow] [(symbol=? curr-color 'flashing-red) 'flashing-red] [else (error 'turn "fell off cond?!")] ; It's already an error in beginning-student, to fall off the end of a cond. ; So I show this just for fun. (But in full-racket it's not an error, ; even when I wish it was, so in full-racket I *may* write such an `else`.) )) ; Task: write penalty-for-running-a-light. (check-expect (penalty-for-running-a-light 'red) 50) (check-expect (penalty-for-running-a-light 'yellow) 0) (check-expect (penalty-for-running-a-light 'green) 0) (check-expect (penalty-for-running-a-light 'flashing-yellow) 0) (check-expect (penalty-for-running-a-light 'flashing-red) 0) ; penalty-for-running-a-light : slc -> non-negative-real ; Return the fine for running a stoplight, in USD. ; (define (penalty-for-running-a-light curr-color) (cond [(symbol=? curr-color 'red) 50] [(symbol=? curr-color 'yellow) 0] [(symbol=? curr-color 'green) 0] [(symbol=? curr-color 'flashing-yellow) 25] [(symbol=? curr-color 'flashing-red) 99] )) ; Step 3, TEMPLATE, for ANY function processing a slc: ; func-for-slc : slc -> ??? (define (func-for-slc a-slc) (cond [(symbol=? a-slc 'red) ...] [(symbol=? a-slc 'yellow) ...] [(symbol=? a-slc 'green) ...] [(symbol=? a-slc 'flashing-yellow) ...] [(symbol=? a-slc 'flashing-red) ...] )) ; Data Def'n: A taxable income is either: ; - a real number in (-∞, 9325] ("modest"), OR ; - a real number in (9325,37950] ("middle"), OR ; - a real number in (37950,∞) ("high") ; Task: Write a function to return the tax-due, given taxable-income. ; (for single tax-payers; we'll stop after 3 brackets) ; ($9325 => 10%; $37950 => 15%; else 25% ) ; https://taxfoundation.org/2017-tax-brackets/ ; examples of the data: 0 10 9325 9325.01 37949.9999 37950 37950.00001 200000000000 -1 3.14159 #| ; TODO: Step 4: develop test cases: (check-expect (tax 0) 0) (check-expect (tax 10) 1) (check-expect (tax 9325) 932.50) (check-expect (tax 9325.01) 932.5015) (check-expect (tax 9326) 932.65) (check-expect (tax 36900) (+ (* 0.10 9325) (* 0.15 (- 37950 9075))) ) (check-expect (tax 47950) (+ (* 0.10 9325) (* 0.15 (- 37950 9075)) (* 0.25 (- 47950 37950)))) ; tax : number -> number ; return the tax-due, given taxable-income. ; (for single tax-payers; we'll stop after 3 tax-tiers) #| (define (tax income) (cond [(<= income 9325) (* 0.10 income)] [(<= income 36900) (+ (* 0.10 9325) (* 0.15 (- income 9325)))] [else (let* {[tier2 (- 37950 9325)] [excess (- income 37950)]} (+ (* 0.10 9075) (* 0.15 tier2) (* 0.25 excess)))])) ; Update: ; a taxable-income-entry is either: ; - 'exempt (a claim that income is exempt-- tax-treaty?), OR ; - #false (represents no taxes filed!), OR ; - a real number in (-∞, 9325] ("modest"), OR ; - a real number in (9325,37950] ("middle"), OR ; - a real number in (37950,∞) ("high") ; Examples of the data -- taxable-income-entry: 10000 37000.5 6000 'exempt #false ; template (define (function-for-tie a-tie) (cond [(symbol? a-tie) ...] [(false? a-tie) ...] [(and (real? a-tie) (<= a-tie 9075)) ...] [... ...] [... ...]))) ; (**) or, collapse the last three cases, and just say it's a "taxable-income" ; as previously defined? |# #| (define (func-for-taxable-income-entry a-tie) (cond [(symbol? a-tie) ...] [(boolean? a-tie) ...] [(<= a-tie 9075) ...] [.. ..] [.. ..]) ; DESIGN QUESTION: ; Should we make `tax2` call `tax` as a helper? ; I'd say, Answer: depending on our data-def'n: ; if we included 5 branches in 'taxable-income-entry', we should have 5 branches. ; Otherwise three. ; But that just begs the question: what is the right data-def'n -- ; should it have 'exempt,#f,number or should it have 5 branches? ; I tend towards the former. |# |#