;; 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 start-design-recipe-after) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) #| `define`: a keyword to bind an identifier to a value: |# (define n 37) (define m (* n 99)) (define ϕ (/ (+ 1 (sqrt 5)) 2)) (define fname "Ian") (define lname "B-meister") ; Syntax for define-a-variable: ; ( define ) #| The Design Recipe (take 1 -- primitive types only) ------- per function: 4. tests 5. stub : header, signature, purpose statement, stub 7. complete the body-expression 8. watch your tests pass |# ;;;;;;;;;;;; Example, of design recipe ;;;;;;;;;;;;;;;;;;;;; ; `check-expect` and `check-within` are part of the language. ; Test-cases include an actual-call (with specific inputs), ; and a specific expected-result. They are *runnable code*! ; ; (comparable to junit's `AssertEquals(Object,Object)` ; and `AssertEquals(double,double,double)`). (check-within (pizza-area 0) 0 0.00001) (check-within (pizza-area 2) 3.14159 0.00001) (check-within (pizza-area 20) 314.159 0.001) (check-within (pizza-area 18) 254.5 0.1) (check-within (pizza-area 20.7) 336.5 0.1) ; It's also fine to use `pi` in your expected-result: (check-within (pizza-area 2) pi 0.0000001) (check-within (pizza-area 20) (* 100 pi) 0.000000001) ; pizza-area : real? -> real? ; pizza-area : non-negative real -> non-negative real ; Return the area of a pizza ... of diameter `d` ; The area (in sq.in.) of a pizza, whose diameter is `diam` (in inches) ; (define (pizza-area d) ; (-> real? real?) (* pi (/ d 2) (/ d 2))) ; New syntax: `define` for functions. ; Note how it mirrors how the function is called (but params instead of argument-expressions). ; Syntax for define-a-function: ; ( define ( ...) ) ; monogram : string string -> string ; Given a first name and last name, return a monogram with initials: ; `first-name`,`last-name` must both be non-empty. ; (define (monogram first-name last-name) (string-append (string-downcase (substring first-name 0 1)) "." (string-downcase (substring last-name 0 1)) ".")) ;;; EXAMPLE: Together, we'll write: `monogram`: ; Given a first name and last name, return a monogram with initials: (check-expect (monogram "Ian" "Barland") "i.b.") (check-expect (monogram "averylongnamejasgdfreiluyfdviulhiulfsadiou" "jdksljkldfsakjldsfakjlfdasfdkjlsadf") "a.j.") (check-expect (monogram "J" "Z") "j.z.") (check-expect (monogram "9" "Z") "9.z.") ; monogram : string string -> string ; Given a first name and last name, return a monogram with initials: ; `first-name`,`last-name` must both be non-empty. ; #;(define (monogram first-name last-name) ; (-> string string string) (string-append (initialize first-name) (initialize last-name))) ;; Now, let's re-factor `monogram`! #| TODO in class |# (check-expect (initialize "Ian") "i.") (check-expect (initialize "J") "j.") ; initialize : string -> string ; return the first letter, downcased, followed by `.` (define (initialize word) (string (char-downcase (string-ref word 0)) #\.)) ;;; EXAMPLE: Okay, now YOU write: `initialize`: ; Return the first letter of a word downcase'd, followed by ".". (check-expect (initialize "Ian") "i.") #| One reaction to factoring out `initialize` above is: "Gee Barland, you did a bunch of extra work, for a fairly small amount of duplicate-code-elimination." (a) All duplicate code smells bad; (b) Smaller functions leads to better testing-via-unit-tests; it reduces the need for printf-debugging or stepping with a debugger. (c) The helper-function might even be useful in its own right. |# ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;; Bonus full-racket code-teaser ;;;;;;;;;;;;;;;;;;;;;;;;; #| As an example of (c) above, AND a preview of the higher-order function `map` that we'll discuss later, here's another function. (You are NOT expected to be able to sit down and write this ...yet!) The following code uses the full-racket language; copy/paste the contents of the #|...|# below into a new DrRacket window, and select: Languages > Choose Language... > The Racket Language ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |# #| #lang racket (require rackunit) ; initialize: non-empty-string -> string ; Return the first letter of a word downcased, following by ".". (define (initialize wrd) (string-append (string (char-downcase (string-ref wrd 0))) ".")) (check-equal? (initialize "Ke$ha") "k.") (check-equal? (initialize "z") "z.") ; acronymize : string -> string ; Given a multi-word phrase, return its acronym. ; (define (acronymize phrase) (apply string-append (map initialize (string-split phrase)))) (check-equal? (acronymize "Self contained underwater breathing apparatus") "s.c.u.b.a.") #| ;; VERSION 2 (define COMMON-WORDS (map symbol->string '(the of and or a))) ; acronymize : string -> string ; Given a multi-word phrase, return its acronym. ; Ignore any `words-to-exclude`. ; (define (acronymize phrase [words-to-exclude empty]) (apply string-append (map initialize (filter (λ(wrd) (not (member wrd words-to-exclude))) (regexp-split #px" |-" (string-downcase phrase)))))) (check-equal? (acronymize "Self contained underwater breathing apparatus") "s.c.u.b.a.") (check-equal? (acronymize "The light-amplified stimulated emission of radiation" COMMON-WORDS) "l.a.s.e.r.") ;;; Again, to be clear: ;;; In this class we will NOT use full-racket, nor worry about regexp's etc. ;;; (We will, though, use `map` in intermediate-student, in a few weeks.) |# |#