Racket Essentials

@wusyong, 吳昱緯

Simple Values

Numbers

1
3.14
1/2
6.02e+23
1+2i
9999999999999999999999

Boolean

  • #t for true
  • #f for false

In conditionals, however, all non-#f values are treated as true.

Strings

"Hello, world!"
"Benjamin \"Bugsy\" Siegel"
"λx:(μα.α→α).xx"
> 1.0000
1.0
> "Bugs \u0022Figaro\u0022 Bunny"
"Bugs \"Figaro\" Bunny"

Simple Definitions and Expressions

A program module is written as

#lang ‹langname› ‹topform›*

Definitions

( define ‹id› ‹expr› )
( define ( ‹id› ‹id›* ) ‹expr›+ )
(define pie 3)             ; defines pie to be 3
 
(define (piece str)        ; defines piece as a function
  (substring str 0 pie))   ;  of one argument
 
> pie
3
> (piece "key lime")
"key"  

Definitions

Multi-expression but with side effect:

(define (bake flavor)
  (printf "preheating oven...\n")
  (string-append flavor " pie"))
 
> (bake "apple")
preheating oven...
"apple pie"

Single expression without side effect

(define (nobake flavor)
  string-append flavor "jello")

> (nobake "green")
"jello"

Identifiers

Excluding the special characters:

( ) [ ] { } " , ' ` ; # | \

+
integer?
pass/fail
Hfuhruhurr&Uumellmahaye
john-jacob-jingleheimer-schmidt
a-b-c+1-2-3

Function Calls

Procedure applications in more traditional terminology

> (string-append "rope" "twine" "yarn")  ; append strings
"ropetwineyarn"
> (substring "corduroys" 0 4)            ; extract a substring
"cord"
> (string-length "shoelace")             ; get a string's length
8
> (string? "Ceci n'est pas une string.") ; recognize strings
#t
> (string? 1)
#f
> (sqrt 16)                              ; find a square root
4
> (sqrt -16)
0+4i
> (+ 1 2)                                ; add numbers
3
> (- 2 1)                                ; subtract numbers
1
> (< 2 1)                                ; compare numbers
#f
> (>= 2 1)
#t
> (number? "c'est une number")           ; recognize numbers
#f
> (number? 1)
#t
> (equal? 6 "half dozen")                ; compare anything
#f
> (equal? 6 6)
#t
> (equal? "half dozen" "half dozen")
#t

Function Calls

( ‹expr› ‹expr›* )
(define (double v)
  ((if (string? v) string-append +) v v))
 
> (double "mnah")
"mnahmnah"
> (double 5)
10

Conditionals: if

( if ‹expr› ‹expr› ‹expr› )
> (if (> 2 3)
      "bigger"
      "smaller")

"smaller"

(define (reply s)
  (if (equal? "hello" (substring s 0 5))
      "hi!"
      "huh?"))
  
> (reply "hello racket")
"hi!"
> (reply "λx:(μα.α→α).xx")
"huh?"

Conditionals: if

Nesting if expressions

(define (reply s)
  (if (string? s)
      (if (equal? "hello" (substring s 0 5))
          "hi!"
          "huh?")
      "huh?"))
(define (reply s)
  (if (if (string? s)
          (equal? "hello" (substring s 0 5))
          #f)
      "hi!"
      "huh?"))

Conditionals: and/or

( and ‹expr›* )
( or ‹expr›* )
(define (reply s)
  (if (and (string? s)
           (>= (string-length s) 5)
           (equal? "hello" (substring s 0 5)))
      "hi!"
      "huh?"))
 
> (reply "hello racket")
"hi!"
> (reply 17)
"huh?"

Conditionals: cond

( cond {[ ‹expr› ‹expr›* ]}* )
(define (reply-more s)
  (cond
   [(equal? "hello" (substring s 0 5))
    "hi!"]
   [(equal? "goodbye" (substring s 0 7))
    "bye!"]
   [(equal? "?" (substring s (- (string-length s) 1)))
    "I don't know"]
   [else "huh?"]))
 
> (reply-more "hello racket")
"hi!"
> (reply-more "goodbye cruel world")
"bye!"
> (reply-more "what is your favorite color?")
"I don't know"
> (reply-more "mine is lime green")
"huh?"

Anonymous Functions with lambda

( lambda ( ‹id›* ) ‹expr›+ )
> (lambda (s) (string-append s "!"))
#<procedure>
> (twice (lambda (s) (string-append s "!"))
         "hello")
"hello!!"
> (twice (lambda (s) (string-append s "?!"))
         "hello")
"hello?!?!"

Anonymous Functions with lambda

Function that generates function

> (lambda (s) (string-append s "!"))
#<procedure>
> (twice (lambda (s) (string-append s "!"))
         "hello")
"hello!!"
> (twice (lambda (s) (string-append s "?!"))
         "hello")
"hello?!?!"
> (define louder (make-add-suffix "!"))
> (define less-sure (make-add-suffix "?"))
> (twice less-sure "really")
"really??"
> (twice louder "really")
"really!!"

Anonymous Functions with lambda

‹expr› could be a lambda form

(define (louder s)
  (string-append s "!"))
 
(define louder
  (lambda (s)
    (string-append s "!")))

> louder
#<procedure:louder>

Local Binding: define

( define ( ‹id› ‹id›* ) ‹definition›* ‹expr›+ )
( lambda ( ‹id›* ) ‹definition›* ‹expr›+ )
(define (converse s)
  (define (starts? s2) ; local to converse
    (define len2 (string-length s2))  ; local to starts?
    (and (>= (string-length s) len2)
         (equal? s2 (substring s 0 len2))))
  (cond
   [(starts? "hello") "hi!"]
   [(starts? "goodbye") "bye!"]
   [else "huh?"]))
 
> (converse "hello!")
"hi!"
> (converse "urp")
"huh?"
> starts? ; outside of converse, so...
starts?: undefined;
 cannot reference an identifier before its definition
  in module: top-level

Local Binding: let/let*

( let ( {[ ‹id› ‹expr› ]}* ) ‹expr›+ )
> (let ([x (random 4)]
        [o (random 4)])
    (cond
     [(> x o) "X wins"]
     [(> o x) "O wins"]
     [else "cat's game"]))

"O wins"

> (let* ([x (random 4)]
         [o (random 4)]
         [diff (number->string (abs (- x o)))])
    (cond
     [(> x o) (string-append "X wins by " diff)]
     [(> o x) (string-append "O wins by " diff)]
     [else "cat's game"]))

"X wins by 2"

Lists, Iteration, and Recursion

> (list "red" "green" "blue")
'("red" "green" "blue")
> (list 1 2 3 4 5)
'(1 2 3 4 5)
> (length (list "hop" "skip" "jump"))        ; count the elements
3
> (list-ref (list "hop" "skip" "jump") 0)    ; extract by position
"hop"
> (list-ref (list "hop" "skip" "jump") 1)
"skip"
> (append (list "hop" "skip") (list "jump")) ; combine lists
'("hop" "skip" "jump")
> (reverse (list "hop" "skip" "jump"))       ; reverse order
'("jump" "skip" "hop")
> (member "fall" (list "hop" "skip" "jump")) ; check for an element
#f

Predefined List Loops: map

> (map sqrt (list 1 4 9 16))
'(1 2 3 4)
> (map (lambda (i)
         (string-append i "!"))
       (list "peanuts" "popcorn" "crackerjack"))
'("peanuts!" "popcorn!" "crackerjack!")

> (map (lambda (s n) (substring s 0 n))
       (list "peanuts" "popcorn" "crackerjack")
       (list 6 3 7))
'("peanut" "pop" "cracker")

Predefined List Loops: andmap/ormap

> (andmap string? (list "a" "b" "c"))
#t
> (andmap string? (list "a" "b" 6))
#f
> (ormap number? (list "a" "b" 6))
#t

Predefined List Loops: filter

> (filter string? (list "a" "b" 6))
'("a" "b")
> (filter positive? (list 1 -2 6 7 0))
'(1 6 7)

Predefined List Loops: filter

> (foldl (lambda (elem v)
           (+ v (* elem elem)))
         0
         '(1 2 3))
14

List Iteration from Scratch

first/rest/cons/empty/empty?

> (first (list 1 2 3))
1
> (rest (list 1 2 3))
'(2 3)

> empty
'()
> (cons "head" empty)
'("head")
> (cons "dead" (cons "head" empty))
'("dead" "head")

> (empty? empty)
#t
> (empty? (cons "head" empty))
#f
> (cons? empty)
#f
> (cons? (cons "head" empty))
#t

List Iteration from Scratch

create your own length and map

(define (my-length lst)
  (cond
   [(empty? lst) 0]
   [else (+ 1 (my-length (rest lst)))]))
 
> (my-length empty)
0
> (my-length (list "a" "b" "c"))
3

(define (my-map f lst)
  (cond
   [(empty? lst) empty]
   [else (cons (f (first lst))
               (my-map f (rest lst)))]))
 
> (my-map string-upcase (list "ready" "set" "go"))
'("READY" "SET" "GO")

Tail Recursion

Problem: my-length takes O(n) space

Solution: define local function to store len

(define (my-length lst)
  ; local function iter:
  (define (iter lst len)
    (cond
     [(empty? lst) len]
     [else (iter (rest lst) (+ len 1))]))
  ; body of my-length calls iter:
  (iter lst 0))

Recursion versus Iteration

Tail call optimization

Pairs, Lists, and Racket Syntax

Result of cons is actually a pair.

> (cons 1 2)
'(1 . 2)
> (cons "banana" "split")
'("banana" . "split")

Pairs, Lists, and Racket Syntax

  • cons? is same as pair?
  • first is same as car
  • rest is same as cdr
> (car (cons 1 2))
1
> (cdr (cons 1 2))
2
> (pair? empty)
#f
> (pair? (cons 1 2))
#t
> (pair? (list 1 2 3))
#t

Pairs, Lists, and Racket Syntax

Some cases that (might) confuse you:

> (cons (list 2 3) 1)
'((2 3) . 1)

> (cons 1 (list 2 3))
'(1 2 3)

Non-list pairs are used intentionally, sometimes.

Pairs, Lists, and Racket Syntax

> (cons 0 (cons 1 2))
'(0 1 . 2)

Use the dot notation unless the dot is immediately followed by an open parenthesis.

  • ‘(0 . (1 . 2)) becomes ‘(0 1 . 2)
  • ‘(1 . (2 . (3 . ()))) becomes ‘(1 2 3).

Quoting Pairs

  • If an element of a list is itself a list, no quote mark is printed for the inner list.
  • quote form can express the same way that the list prints.
> (list (list 1) (list 2 3) (list 4))
'((1) (2 3) (4))
> (quote ("red" "green" "blue"))
'("red" "green" "blue")
> (quote ((1) (2 3) (4)))
'((1) (2 3) (4))
> (quote ())
'()

Quoting Pairs

quote form works with the dot notation, too.

> (quote (1 . 2))
'(1 . 2)
> (quote (0 . (1 . 2)))
'(0 1 . 2)

Lists of any kind can be nested.

> (list (list 1 2 3) 5 (list "a" "b" "c"))
'((1 2 3) 5 ("a" "b" "c"))
> (quote ((1 2 3) 5 ("a" "b" "c")))
'((1 2 3) 5 ("a" "b" "c"))

Symbols with quote

A value prints like a quoted identifier is a symbol.

> (quote jane-doe)
'jane-doe

> map
#<procedure:map>
> (quote map)
'map
> (symbol? (quote map))
#t
> (symbol? map)
#f
> (procedure? map)
#t
> (string->symbol "map")
'map
> (symbol->string (quote map))
"map"

Symbols with quote

quote for a list automatically applies itself to nested lists.

> (car (quote (road map)))
'road
> (symbol? (car (quote (road map))))
#t
> (quote (road map))
'(road map)

Symbols with quote

quote form has no effect on a literal expression

> (quote 42)
42
> (quote "on the record")
"on the record"

Abbreviating quote with '

> '(1 2 3)
'(1 2 3)
> 'road
'road
> '((1 2 3) road ("a" "b" "c"))
'((1 2 3) road ("a" "b" "c"))

Abbreviating quote with '

A ' expands to a quote form in quite a literal way.

> (car ''road)
'quote
> (car '(quote road))
'quote
> (quote (quote road))
''road
> '(quote road)
''road
> ''road
''road

Lists and Racket Syntax

  • Reader layer, which turns a sequence of characters into lists, symbols, and other constants
  • Expander layer, which processes the lists, symbols, and other constants to parse them as an expression.
> (+ 1 . (2))
3
> (1 . < . 2)
#t
> '(1 . < . 2)
'(< 1 2)