#lang plai ;; Make sure you pick the "Use the language declared in the source" ;; language in DrRacket (use the Language|Choose Language ... menu item) ;; This is a comment that continues to the end of the line. ; One semi-colon is enough. ;; A common convention is to use two semi-colons for ;; multiple lines of comments, and a single semi-colon ;; when adding a comment on the same ;; line as code. #| This is a block comment, which starts with "#|" and ends with a "|#". Block comments can be nested, which is why I can name the start and end tokens in this comment. |# ;; #; comments out a single expression ;; (used below to comment out error examples) #;(/ 1 0) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Built-in atomic data ;; Booleans true false #t ; traditional name for true #f ; ditto for false ;; Numbers 1 0.5 1/2 ; this is a literal fraction, not a division operation 1+2i ; complex number ;; Strings "apple" "banana cream pie" ;; Symbols 'apple 'banana-cream-pie 'a->b '#%$^@*&?! ;; Characters (unlikely to be useful) #\a #\b #\A #\space ; same as #\ (with a space after the \) ;; Empty list empty ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Built-in functions on atomic data not + - * ; etc. < > = <= >= string-append string=? string-ref eq? ; mostly for symbols equal? ; most other things char->integer integer->char empty? number? real? symbol? string? char? ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Basic expression forms ;; Procedure application ;; ( *) (not true) ; => false (+ 1 2) ; => 3 (< 2 1) ; => false (= 1 1) ; => true (string-append "a" "b") ; => "ab" (string-ref "apple" 0) ; => #\a (eq? 'apple 'apple) ; => true (eq? 'apple 'orange) ; => false (eq? (string-append "app" "le") "apple") ; => false, probably (equal? (string-append "app" "le") "apple") ; => true (string=? "apple" "apple"); => true (char->integer #\a) ; => 97 (integer->char 65) ; => #\A (empty? empty) ; => true (number? empty) ; => false (number? 12) ; => true (real? 1+2i) ; => false ;; Conditionals ;; (cond ;; [ ]*) ;; (cond ;; [ ]* ;; [else ]) (cond ; [(< 2 1) 17] ; [(> 2 1) 18]) ; => 18 (cond ; second expression not evaluated [true 8] ; [false (* 'a 'b)]) ; => 8 (cond ; in fact, second test not evaluated [true 9] ; [(+ 'a 'b) (* 'a 'b)]) ; => 9 (cond ; any number of cond-lines allowed [(< 3 1) 0] ; [(< 3 2) 1] ; [(< 3 3) 2] ; [(< 3 4) 3]) ; => 3 (cond ; else allowed as last case [(eq? 'a 'b) 0] ; [(eq? 'a 'c) 1] ; [else 2]) ; => 2 (cond [(< 3 1) 1] [(< 3 2) 2]) ; => prints nothing ;; If ;; (if ) (if (< 3 1) ; simpler form for single test "apple" ; "banana") ; => "banana" ;; And and Or ;; (and *) ;; (or *) (and true true) ; => true (and true false) ; => false (and (< 2 1) true) ; => false (and (< 2 1) (+ 'a 'b)) ; => false (second expression is not evaluated) (or false true) ; true (or false false) ; false (or (< 1 2) (+ 'a 'b)) ; => true (second expression is not evaluated) (and true true true true) ; => true (or false false false) ; => false (and true 1) ; => 1, bcause only `false' is false ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Built-in compound data ;; Lists (cons 1 empty) ; => (list 1) (cons 'a (cons 2 empty)) ; => (list 'a 2) (list 1 2 3) ; => (list 1 2 3) (list 1 2 3 empty) ; => (list 1 2 3 empty) (append (list 1 2) empty) ; => (list 1 2) (append (list 1 2) (list 3 4)) ; => (list 1 2 3 4) (append (list 1 2) (list 'a 'b) (list true)) ; => (list 1 2 'a 'b true) (first (list 1 2 3)) ; => 1 (rest (list 1 2 3)) ; => (list 2 3) (first (rest (list 1 2))) ; => 2 (list-ref '(1 2 3) 2) ; => 3 ;; '(...) creates a list, and it distributes over elements ;; ditto for '{} '(1 2 3) ; => (list 1 2 3) '(a b) ; => (list 'a 'b) '((1 2) (3 4)) ; => (list (list 1 2) (list 3 4)) '10 ; => 10 '{{{c}}} ; => (list (list (list 'c))) (cons 1 2) ; => (cons 1 2), which is a non-list pair ;; Vectors (vector 1 2 3 4) ; => (vector 1 2 3 4) (vector-ref (vector 1 2) 0) ; => 1 ; '#(...) creates a vector, and #(...) is self-quoting '#(1 2) ; => (vector 1 2) #(1 (2 3)) ; => (vector 1 (list 2 3)) #(a b) ; => (vector 'a 'b) ;; Boxes (box 1) ; => (box 1) (unbox (box 1)) ; => 1 '#&1 ; => (box 1) #&1 ; => (box 1) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Definitions ;; Defining constants ;; (define ) (define PI 3.14159) (* PI 10) ; => 31.4159 ;; Defining functions ;; (define ( *) ) (define (circle-area r) (* PI r r)) (circle-area 10) ; => 314.159 (define (is-odd? x) (if (zero? x) false (is-even? (- x 1)))) (define (is-even? x) (if (zero? x) true (is-odd? (- x 1)))) (is-odd? 12) ; => false ;; Defining datatypes ;; (define-type ;; [ ( )*]*) (define-type Animal [snake (name symbol?) (weight number?) (food symbol?)] [tiger (name symbol?) (stripe-count number?)]) (snake 'Slimey 10 'rats) ; => (snake 'Slimey 10 'rats) (tiger 'Tony 12) ; => (tiger 'Tony 12) #;(snake 10 'Slimey 5) ; => error: 10 is not a symbol (Animal? (snake 'Slimey 10 'rats)) ; => true (Animal? (tiger 'Tony 12)) ; => true (Animal? 10) ; => false (snake-name (snake 'Slimey 10 'rats)) ; => 'Slimey (tiger-name (tiger 'Tony 12)) ; => 'Tony (snake? (snake 'Slimey 10 'rats)) ; => true (tiger? (snake 'Slimey 10 'rats)) ; => false ;; A type can have any number of variants: (define-type Shape [square (side number?)] [circle (radius number?)] [triangle (height number?) (width number?)]) (Shape? (triangle 10 12)) ; => true ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Local binding forms ;; Local ;; (local [*] ) (local [(define x 10)] (+ x x)) ; => 20 #;x ; => error: unbound identifier (define (to-the-fourth x) (local [(define (squared n) (* n n))] (* (squared x) (squared x)))) (to-the-fourth 10) ; => 10000 (local [(define (odd? x) (if (zero? x) false (even? (- x 1)))) (define (even? x) (if (zero? x) true (odd? (- x 1))))] (odd? 12)) ; => false ;; the 'local' can be skipped in the body of a function ;; (or in a case of a 'cond' expression): (define (to-the-sixteeth x) (define (to-the-eighth n) (* (to-the-fourth n) (to-the-fourth n))) (* (to-the-eighth x) (to-the-eighth x))) ;; Let (more standard but less regular, so not used in this course) ;; (let ([ ]*) ) (let ([x 10] [y 11]) (+ x y)) ; => 21 (let ([x 0]) (let ([x 10] [y (+ x 1)]) (+ x y))) ; => 11 (let ([x 0]) (let* ([x 10] [y (+ x 1)]) (+ x y))) ; => 21 ;; Datatype case dispatch ;; (type-case ;; [ (*) ]*) ;; (type-case ;; [ (*) ]* ;; [else ]) (type-case Animal (snake 'Slimey 10 'rats) [snake (n w f) n] [tiger (n sc) n]) ; => 'Slimey (define (animal-name a) (type-case Animal a [snake (n w f) n] [tiger (n sc) n])) (animal-name (snake 'Slimey 10 'rats)) ; => 'Slimey (animal-name (tiger 'Tony 12)) ; => 'Tony #;(animal-name 10) ; => error: 10 is not an Animal #;(type-case Food ...) ; => error: Food is not a defined type #;(define (animal-weight a) (type-case Animal a [snake (n w f) w])) ; => error: missing tiger case (define (animal-weight a) (type-case Animal a [snake (n w f) w] [else false])) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; First-class functions ;; Anonymous function: ;; (lambda (*) ) (lambda (x) (+ x 1)) ; => (lambda (a1) ...) ((lambda (x) (+ x 1)) 10) ; => 11 (define add-one (lambda (x) (+ x 1))) (add-one 10) ; => 11 (define (make-adder n) (lambda (m) (+ m n))) (make-adder 8) ; => (lambda (a1) ...) (define add-five (make-adder 5)) (add-five 12) ; => 17 ((make-adder 5) 12) ; => 17 (map (lambda (x) (* x x)) '(1 2 3)) ; => (list 1 4 9) (andmap (lambda (x) (< x 10)) '(1 2 3)) ; => true (andmap (lambda (x) (< x 10)) '(1 20 3)) ; => false (ormap (lambda (x) (< x 10)) '(1 20 a)) ; => true ;; The apply function may be useful eventually: (define f (lambda (a b c) (+ a (- b c)))) (define l '(1 2 3)) #;(f l) ; => error: f expects 3 arguments (apply f l) ; => 0 ;; apply is most useful with functions that accept any ;; number of arguments: (apply + '(1 2 3 4 5)) ; => 15 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Side-effects ;; IMPORTANT: in this class using a side-effect is ;; usually wrong; avoid side-effects ;; unless explicitly directed ;; set! and begin ;; (set! ) ;; (begin *) (define count 0) (set! count (+ count 1)) ; => count ; => 1 (begin (set! count (+ count 1)) count) ; => 2 (local [(define x 0)] ; note: demonstrates set! in local, (begin ; but it's terrible style (set! x (list x)) ; (set! x (list x)) ; x)) ; => (list (list 0)) ;; set-box! is a function: (define B (box 10)) (set-box! B 12) ; => B ; => (box 12) (unbox B) ; => 12 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Testing ;; test, test/pred, and test/exn functions: (test (+ 5 5) 10) ; => (list 'good 10 10) (test (+ 5 4) 10) ; => (list 'bad 9 10) (test/pred (* 2 3) even?) ; => (list 'good 6 true) (test/pred (* 3 3) even?) ; => (list 'bad 9 false) (test/exn (+ 1 'a) "expects type ") ; => (list 'good ....) (test/exn (+ 1 2) "expects type ") ; => (list 'bad ....) (test/exn (/ 1 0) "expects type ") ; => (list 'bad ....) (print-only-errors #t) ; only show testing output when there are failures ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; More information ;; Use the "Racket Documentation" item in DrRacket's "Help" menu ;; See "The Racket Guide" ;; and "Programming Languages: Application and Interpretation" (under Teaching)