#lang class/1 ;; Parametric interfaces ;; --------------------- ;; An [Listof X] implements ;; - all : [Question X] -> Boolean ;; - filter : [Question X] -> [Listof X] ;; A [NEListof X] implements ;; - mostest : [Comparison X] -> X ;; A [Question X] implements ;; - ask : X -> Boolean ;; A [Comparison X] implements ;; - compare : X X -> Boolean ;; Gender ;; ------ ;; A Gender implements ;; - is-male? : -> Boolean ;; - is-female? : -> Boolean (require "gender.rkt") ; provides m, f. ;; Runner ;; ------ ;; A Runner is a (new runner% String Natural Natural Natural Gender) ;; Interp: runnner with name, age in years, bib number, ;; time in minutes, & gender. (define-class runner% (fields name age bib time gender)) ;; Example runners (define johnny (new runner% "Kelley" 97 1001 351 m)) (define bobby (new runner% "Cheruiyot" 33 8 127 m)) (define roberta (new runner% "Gibb" 23 121 200 f)) ;; [Question Runner] ;; ----------------- ;; A [Question Runner] implements ;; - ask : Runner -> Boolean ;; Ask this question of the runner. (define-class is-old% ;; ask : Runner -> Boolean ;; Is the given runner older than 50? (check-expect ((new is-old%) . ask johnny) true) (check-expect ((new is-old%) . ask roberta) false) (define (ask r) (> (r . age) 50))) (define-class is-fast% ;; ask : Runner -> Boolean ;; Is the given runner fast (time less than 250)? (check-expect ((new is-fast%) . ask johnny) false) (check-expect ((new is-fast%) . ask roberta) true) (define (ask r) (< (r . time) 250))) (define-class is-male% ;; ask : Runner -> Boolean ;; Is the given runner male? (check-expect ((new is-male%) . ask johnny) true) (check-expect ((new is-male%) . ask roberta) false) (define (ask r) (r . gender . is-male?))) (define-class is-female% ;; ask : Runner -> Boolean ;; Is the given runner female? (check-expect ((new is-female%) . ask johnny) false) (check-expect ((new is-female%) . ask roberta) true) (define (ask r) (r . gender . is-female?))) ;; [Comparison Runner] ;; ------------------- ;; A [Comparison Runner] implements ;; - compare : Runner Runner -> Boolean ;; Does the first runner compare better than the second? (define-class is-younger% ;; compare : Runner Runner -> Boolean ;; Is r1 younger than r2? (check-expect ((new is-younger%) . compare johnny roberta) false) (check-expect ((new is-younger%) . compare roberta johnny) true) (define (compare r1 r2) (< (r1 . age) (r2 . age)))) (define-class is-older% ;; compare : Runner Runner -> Boolean ;; Is r1 older than r2? (check-expect ((new is-older%) . compare johnny roberta) true) (check-expect ((new is-older%) . compare roberta johnny) false) (define (compare r1 r2) (> (r1 . age) (r2 . age)))) (define-class is-faster% ;; compare : Runner Runner -> Boolean ;; Is r1 faster than r2? (check-expect ((new is-faster%) . compare johnny roberta) false) (check-expect ((new is-faster%) . compare roberta johnny) true) (define (compare r1 r2) (< (r1 . time) (r2 . time)))) (define-class is-slower% ;; compare : Runner Runner -> Boolean ;; Is r1 slower than r2? (check-expect ((new is-slower%) . compare johnny roberta) true) (check-expect ((new is-slower%) . compare roberta johnny) false) (define (compare r1 r2) (> (r1 . time) (r2 . time)))) (define-class has-longer-name% ;; compare : Runner Runner -> Boolean ;; Does r1 have a longer name than r2? (check-expect ((new has-longer-name%) . compare johnny roberta) true) (check-expect ((new has-longer-name%) . compare roberta johnny) false) (define (compare r1 r2) (> (string-length (r1 . name)) (string-length (r2 . name))))) ;; [Listof Runner] ;; --------------- ;; A [Listof Runner] implements ;; - fastest-old : -> Runner ;; Get fastest runner older than 50 in this list. ;; - fastest-male : -> MaybeRunner ;; Get fastest male runner in this list. ;; - all-old? : -> Boolean ;; Are all the runners in this list over 50? ;; - all-fast? : -> Boolean ;; Are all the runners in this list faster than 250? ;; - males : -> LoR ;; Get list of male runners in this list. ;; - females : -> LoR ;; Get list of female runners in this list. ;; - sort-asc-name : -> LoR ;; Get list of runners sorted in ascending order by name. ;; - sort-asc-time : -> LoR ;; Get list of runners sorted in ascending order by time. ;; A [NEListof Runner] implements ;; - fastest : -> Runner ;; Get fastest runner in this list. ;; - slowest : -> Runner ;; Get slowest runner in this list. ;; - youngest : -> Runner ;; Get youngest runner in this list. ;; - oldest : -> Runner ;; Get oldest runner in this list. ;; - mostest : [Comparison Runner] -> Runner ;; Abstract class for [Listof X]. (define-class list% ;; Only defined for [Listof Runner]. (define (all-old?) (this . all (new is-old%))) (define (all-fast?) (this . all (new is-fast%))) (define (males) (this . filter (new is-male%))) (define (females) (this . filter (new is-female%)))) (define-class mt% ; implements [Listof X] (super list%) ;; all : [Question X] -> Boolean (define (all q) true) ;; filter : [Question X] -> [Listof X] (define (filter q) this) ;; mostest/acc : X [Comparison X] -> X (define (mostest/acc x rc) x)) (define-class cons% ; implements [Listof X], [NEListof X] (super list%) (fields first rest) ;; An alternative definition of all that uses functions ;; instead of function objects. ;; all-f : [Runner -> Boolean] -> Boolean #; (define (all-f p) (and (p (this . first)) (this . rest . all-f p))) ;; all : [Question X] -> Boolean (define (all q) (and (q . ask (this . first)) (this . rest . all q))) ;; filter : [Question X] -> [Listof X] (define (filter q) (cond [(q . ask (this . first)) (new cons% (this . first) (this . rest . filter q))] [else (this . rest . filter q)])) ;; mostest : [Comparison X] -> X (define (mostest rc) (this . rest . mostest/acc (this . first) rc)) ;; mostest/acc : X [Comparison X] -> X (define (mostest/acc x c) (this . rest . mostest/acc (cond [(c . compare x (this . first)) x] [else (this . first)]) c)) ;; Only defined when this is a [Listof Runner] ;; youngest : -> Runner (define (youngest) (this . mostest (new is-younger%))) ;; oldest : -> Runner (define (oldest) (this . mostest (new is-older%))) ;; fastest : -> Runner (define (fastest) (this . mostest (new is-faster%))) ;; slowest : -> Runner (define (slowest) (this . mostest (new is-slower%)))) ;; Example [Listof Runner] (define rs (new cons% johnny (new cons% bobby (new cons% roberta (new mt%))))) (define mt (new mt%)) (check-expect (rs . fastest) bobby) (check-expect (rs . slowest) johnny) (check-expect (rs . youngest) roberta) (check-expect (rs . oldest) johnny) #| (check-expect (rs . fastest-old) johnny) (check-expect (rs . fastest-male) bobby) |# (check-expect ((new mt%) . all-old?) true) (check-expect ((new mt%) . all-fast?) true) (check-expect (rs . all-old?) false) (check-expect (rs . all-fast?) false) (check-expect ((new cons% johnny (new mt%)) . all-old?) true) (check-expect ((new cons% roberta (new mt%)) . all-fast?) true) (check-expect (rs . males) (new cons% johnny (new cons% bobby (new mt%)))) (check-expect (rs . females) (new cons% roberta (new mt%))) #| (check-expect (rs . sort-asc-name) (new cons% bobby (new cons% roberta (new cons% johnny mt)))) (check-expect (rs . sort-asc-time) (new cons% bobby (new cons% roberta (new cons% johnny mt)))) |#