;; 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 dist-lect02) (read-case-sensitive #t) (teachpacks ((lib "universe.ss" "teachpack" "2htdp") (lib "image.ss" "teachpack" "2htdp"))) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ((lib "universe.ss" "teachpack" "2htdp") (lib "image.ss" "teachpack" "2htdp"))))) ; Earlier, we said that a "type" is a "set of values". ; Btw, what types does Racket have built-in? ; #| - exact numbers (Java: long, int, short, byte) - string - char - inexact numbers (Java: double, float) - boolean - images |# ;;; In Java: the other type is String, Elephant, Car, ... ;;; (really: *reference* to Elephant, *reference* to Car, etc.) ; symbols: ; examples: 'jack 'queen 'red 'yellow 'green 'amy 'george ... ; Can often be used as an enumerated type, ; or like a string that I'll never want to call substring/string-ref/string-concat etc. ; The *only* useful function involving symbols: symbol=? symbol? ; ; symbol=? : symbol, symbol -> boolean ; symbol? : ANY -> boolean ; integer? : ANY -> boolean ; number->string : number -> string ; Examples of evaluation: ; ;(define x 4) #;(/ (+ (- 7) (sqrt (- (* 7 7) (* 4 x 3)))) (* 2 x)) ; What about evaluating?: ; #;(define (root1 a b c) (/ (+ (- b) (sqrt (- (* b b) (* 4 a c)))) (* 2 a))) #;(root1 4 7 (- 7 4)) ; parameter (a,b,c) is a variable-name ; argument (4,7,3) is a *value* that get passed in to a function #| The Law of Scheme: Given an expression, evaluate it to get a value. An Expression is one of: And to evaluate it, you: 1. value 23, "hi", false, #\A, ... - just use that value (duh!) 2. identifier x, char->integer - look up reulst of previous `define` 3. function-application: - Eval exrp0..exprn (expr0 expr1 ... exprn) to get val0, val1, ..., valn (val0 had better be a func!) e.g. (+ 2 (* 3 4) 5); (a) if val0 is a built-in primitive, expr1 is `7` call that with val1...valn, expr2 is `(* 3 4)` and that's your answer. expr3 is `5` (b) if val0 is a user-defined function, expr0 is the abstract func `addition` take the body of the func, subst the params with val1,...,valn Then evaluate *that* for your answer. 4. Special Forms (with their own syntax, and rules-of-evaluation): define -- don't eval the first "argument" and,or -- short-circuit if,cond -- short-circuit: only eval the 2nd *or* 3rd arg, not both define-struct -- stay tuned... |# ; Introducting `if`, and talking about why it's a special form: ; Syntax: ; (if ) ; Semantics: ; Evaluate to get . ; [In the student-languages: had better be a boolean!] ; If is #f, then eval and return that; ; otherwise eval and return that result. ; ; Try in stepper: ;(define n 0) ;(if (= n 0) 23 (/ 1 n)) ; Why does `if` have to be special? ; ; Here's an example of we'd hate the normal law-of-scheme: ; bat-avg: int, int -> real ; Return the batting average, ; or 1.000 at the start of the season. ; (define (bat-avg hits times-at-bat) (if (= times-at-bat 0) 1 (/ hits times-at-bat))) (bat-avg 0 0) (bat-avg 0 203) ; Btw: compare `if` to: ; - Java/etc's ternary operator: ; return (timesAtBat==0) ? 1 : hits/timesAtBat; ; - Excel's `if`: =if(A3=0, 1, B3/A3) ; Similarly, `define` has to be a special form. ; (Why -- what would happen if define were a normal function, ; using the law-of-scheme?) ; Discuss: `and` is a special form. ; Can you show me an expression to convince me it's not a regular function? ; Does `and` *have* to be a special form? If not, why is it one? ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Union types: ;;; How to handle a data-type that can be of type A OR B? ;;; (that is: since types are sets-of-values: ;;; how to handle any value from the set (union A B)? ) ;;; Example: the rank of a playing-card. ;;; (We'll deal with the suit tomorrow.) ; A c-rank is either: ; - an integer (2..10) ; or - a symbol ('jack, 'queen, 'king, 'ace) ; Examples of the data, for c-rank: 5 'queen ;;; Writing code to handle a union type: ;; I want a function to help my bridge-playing freind: ;; you assign 'points' to each card; 2-10 are worth zero ;; but J,Q,K,A are worth 1,2,3,4 resp. ;; A stub function: ; crank-value : c-rank -> int ; compute the bridge-playing value for a given c-rank. (define (crank-value a-cr) (cond [(integer? a-cr) 0] [(symbol? a-cr) (cond [(symbol=? a-cr 'jack) 1] [(symbol=? a-cr 'queen) 2] [(symbol=? a-cr 'king) 3] [(symbol=? a-cr 'ace) 4])])) ;;; test cases (write 'em first!) (check-expect (crank-value 5) 0) (check-expect (crank-value 'queen) 2) ;;; Since we're handling data that can be integer OR character, ;;; we'll use "cond", which is like if-else-if: #;(define (rank-val a-cr) (cond [(integer? a-cr) ...] [(character? a-cr) ...])) ;;; Depending on how paranoid we are, we can add one extra branch ;;; for protection: #;(define (rank-val a-cr) (cond [(integer? a-cr) ...] [(character? a-cr) ...] [else ...])) ;;; (However in the *student* languages, it already signals ;;; an error if you fall off the end of a cond. ;;; I wish all levels did this!) ;;; Aside: the syntax of `cond`: #;(cond [q1 a1] [q2 a2] ... [qn an]) ;;; (Think q,a for question,answer.) ;;; Each of q1..qn is any expression (presumably evals to a boolean), ;;; or it's the word `else` which is equivalent to `#t`. ;;; Each of a1...an are any expression. ;;; ;;; The semantics of cond: ;;; Evaluate q1; if it's true then return result of eval'ing a1; otherwise ;;; Evaluate q2; if it's true then return result of eval'ing q2; otherwise ;;; ... ;;; Evaluate qn; if it's true then return result of eval'ing qn; otherwise ;;; raise an error (in student-languages -- full lang returns (void)). ;;; q1...qn are either ;;; Okay, let's get back to writing rank-val: #;(define (rank-val a-cr) (cond [(integer? a-cr) ...] [(character? a-cr) ...])) ; We fill in each `...`. ; The first is pretty easy. ; The second will be ??? ; rank-val: card-rank -> integer ; ; A few questions you probably have: ; ; Could we collapse the nested conds? ; Yes, but I don't: ; The outer cond is there for a specific reason: ; it follows from the fact that *any* function handling a card-rank ; needs to ask those questions. ; The inner cond is doing work specific to this function. ; ; Could we have used an `if` instead of the outer `cond`? ; Yes, but again we use the `cond` as a signal to other programmers ; that we're doing a *case analysis* on the *type* of the input. ;;;;;;;;;;;;;;;;;;;;;;;;;;; Hour 3 ;;;;;;;;;;;;;;;;;;;;; ; Exercise: write a function that takes in c-rank, and returns ...? ; Let's see how much we can write w/o even knowing WTF ("what the function?") ; A c-rank is either: ; - an integer (2..10) ; or - a symbol ('jack, 'queen, 'king, 'ace) ; Btw, we can write: ; crank? ANY -> boolean ; BUT -- for this class, we'll focus on principles, ; and so if you say a function should take in a c-rank, ; then *your* code doesn't need to check for other types. ; (True, defensive programming is a good practice though.) ; (define (c-rank? any) (or (and (integer? any) (<= 2 any 10)) (and (symbol? any) (or (symbol=? any 'jack) (symbol=? any 'queen) (symbol=? any 'king) (symbol=? any 'ace))))) ;(member any (list 'jack 'queen 'king 'ace)) ; this function takes in a c-rank, and returns a string representing the rank. (define (crank->string a-cr) (cond [(symbol? a-cr) (symbol->string a-cr)] [(integer? a-cr) (number->string a-cr)])) (check-expect (crank->string 5) "5") (check-expect (crank->string 'queen) "queen") ; a template for *any* function handling c-ranks #;(define (func-for-crank a-cr) (cond [(symbol? a-cr) ..] [(integer? a-cr) ..])) ; ; The design recipe: ; http://htdp.org/2003-09-26/Book/curriculum-Z-H-7.html#node_sec_4.4 ; --- per (abstract) data type: ; - data def'n ; - examples of data ; - template (case analysis) ; --- per function: ; - contract, purpose, header ; - test-cases (check-expect) ; - complete function-body ; - case analysis (cond-questions, 1 per data variant) ; - answer for each cases ; - run the tests (trivial) ;;;;;;;;;;;;;;;;; Next stage: define-struct (product type) ; ; Example: (define-struct card (rank suit)) ; rank : c-rank ; suit : symbol (make-card 'queen 'spades) (define my-hand (make-card 2 'clubs)) (card-suit (make-card 'queen 'spades)) ; 'spades (card-rank (make-card 'queen 'spades)) ; 'queen (card-suit my-hand) ; 'clubs (card-rank my-hand) ; 2 (card? (make-card 'queen 'spades)) ; #t (card? my-hand) ; #t (card? 17) ; #f (card? 'clubs) ; #f ; When I define-struct, racket creates four functions for me: ; make-card -- constructor ; card-rank -- accessor ; card-suit -- accessor ; card? -- predicate ; Exercise: give the signature of each of these functions. ; make-card : c-rank, symbol -> card ; card-rank : card -> c-rank ; card-suit : card -> symbol ; card? : ANY -> boolean ; have-a-heart : c-rank -> card ; Return a card of the given rank, in hearts. ; (check-expect (have-a-heart 5) (make-card 5 'hearts)) (check-expect (have-a-heart 'queen) (make-card 'queen 'hearts)) ; have-a-heart : c-rank -> card ; Return a card of the given rank, in hearts. ; (define (have-a-heart a-cr) (make-card a-cr 'hearts))