-
Notifications
You must be signed in to change notification settings - Fork 0
/
06_control_flow.rkt
139 lines (107 loc) · 3.59 KB
/
06_control_flow.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#lang racket ; defines the language we are using
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 6. Control Flow
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Conditionals
(if #t ; test expression
"this is true" ; then expression
"this is false") ; else expression
; => "this is true"
;; In conditionals, all non-#f values are treated as true
(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo)
(if (member 'Groucho '(Harpo Groucho Zeppo))
'yep
'nope)
; => 'yep
;; `cond' chains a series of tests to select a result
(cond [(> 2 2) (error "wrong!")]
[(< 2 2) (error "wrong again!")]
[else 'ok]) ; => 'ok
;;; Pattern Matching
(define (fizzbuzz? n)
(match (list (remainder n 3) (remainder n 5))
[(list 0 0) 'fizzbuzz]
[(list 0 _) 'fizz]
[(list _ 0) 'buzz]
[_ #f]))
(fizzbuzz? 15) ; => 'fizzbuzz
(fizzbuzz? 37) ; => #f
;;; Loops
;; Looping can be done through (tail-) recursion
(define (loop i)
(when (< i 10)
(printf "i=~a\n" i)
(loop (add1 i))))
(loop 5) ; => i=5, i=6, ...
;; Similarly, with a named let
(let loop ([i 0])
(when (< i 10)
(printf "i=~a\n" i)
(loop (add1 i)))) ; => i=0, i=1, ...
;; See below how to add a new `loop' form, but Racket already has a very
;; flexible `for' form for loops:
(for ([i 10])
(printf "i=~a\n" i)) ; => i=0, i=1, ...
(for ([i (in-range 5 10)])
(printf "i=~a\n" i)) ; => i=5, i=6, ...
;;; Iteration Over Other Sequences
;; `for' allows iteration over many other kinds of sequences:
;; lists, vectors, strings, sets, hash tables, etc...
(for ([i (in-list '(l i s t))])
(displayln i))
(for ([i (in-vector #(v e c t o r))])
(displayln i))
(for ([i (in-string "string")])
(displayln i))
(for ([i (in-set (set 'x 'y 'z))])
(displayln i))
(for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3))])
(printf "key:~a value:~a\n" k v))
;;; More Complex Iterations
;; Parallel scan of multiple sequences (stops on shortest)
(for ([i 10] [j '(x y z)])
(printf "~a:~a\n" i j))
; => 0:x 1:y 2:z
;; Nested loops
(for* ([i 2] [j '(x y z)])
(printf "~a:~a\n" i j))
; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z
;; Conditions
(for ([i 1000]
#:when (> i 5)
#:unless (odd? i)
#:break (> i 10))
(printf "i=~a\n" i))
; => i=6, i=8, i=10
;;; Comprehensions
;; Very similar to `for' loops -- just collect the results
(for/list ([i '(1 2 3)])
(add1 i)) ; => '(2 3 4)
(for/list ([i '(1 2 3)] #:when (even? i))
i) ; => '(2)
(for/list ([i 10] [j '(x y z)])
(list i j)) ; => '((0 x) (1 y) (2 z))
(for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10))
i) ; => '(6 8 10)
(for/hash ([i '(1 2 3)])
(values i (number->string i)))
; => '#hash((1 . "1") (2 . "2") (3 . "3"))
;; There are many kinds of other built-in ways to collect loop values:
(for/sum ([i 10]) (* i i)) ; => 285
(for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000
(for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t
(for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t
;; And to use any arbitrary combination, use `for/fold'
(for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10
;; (This can often replace common imperative loops)
;;; Exceptions
;; To catch exceptions, use the `with-handlers' form
(with-handlers ([exn:fail? (lambda (exn) 999)])
(+ 1 "2")) ; => 999
(with-handlers ([exn:break? (lambda (exn) "no time")])
(sleep 3)
"phew") ; => "phew", but if you break it => "no time"
;; Use `raise' to throw exceptions or any other value
(with-handlers ([number? ; catch numeric values raised
identity]) ; return them as plain values
(+ 1 (raise 2))) ; => 2