fixed SICP link
[glow:artanis.git] / src / scheme.wiki
1 ((title . "Learn Scheme in 15 minutes")
2  (authors "Mu Lei known as NalaGinrut <nalaginrut@gmail.com>")
3  (date . 1374652887)
4  (layouts "scheme.sxml"))
5
6 === Learn Scheme in 15 minutes
7
8 <enscript language="scheme">
9 ;; This gives an introduction to Scheme in 15 minutes
10 ;;
11 ;; First make sure you read this text by Peter Norvig:
12 ;; http://norvig.com/21-days.html
13 ;;
14 ;; Then install GNU Guile
15 ;;
16 ;; openSUSE: zypper install guile
17 ;; Debian: apt-get install guile (or see your distro instructions)
18 ;; MacOSX: Building Guile 2.0 on the Mac
19 ;;         http://irrealblog.blogspot.hk/2011/03/building-guile-2.html
20 ;; Windows try web: http://repl.it/languages/Scheme
21 ;;
22 ;; More general information can be found at:
23 ;; http://www.gnu.org/software/guile
24
25 ;; Important warning:
26 ;;
27 ;; Going through this tutorial won't damage your computer unless
28 ;; you get so angry that you throw it on the floor.  In that case,
29 ;; I hereby decline any responsability.  Have fun!
30
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32 ;; 
33 ;; Fire up Scheme:
34 ;; Type 'guile' for GNU Guile
35 ;; Or just use the browser for web version
36 ;;
37 ;; Now look at the prompt:
38
39 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
40 ;;
41 ;; Semi-colons start comments anywhere on a line.
42 ;;
43 ;; Scheme programs are made of symbolic expressions (s-exps):
44 (+ 2 2)
45
46 ;; This symbolic expression reads as "Add 2 to 2".
47
48 ;; Sexps are enclosed into parentheses, possibly nested:
49 (+ 2 (+ 1 1))
50
51 ;; A symbolic expression contains atoms or other symbolic
52 ;; expressions.  In the above examples, 1 and 2 are atoms,
53 ;; (+ 2 (+ 1 1)) and (+ 1 1) are symbolic expressions.
54
55 (+ 3 (+ 1 2))
56 ;; => 6
57
58 ;; `set!' stores a value into a variable:
59 (set! my-name "NalaGinrut")
60
61 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
62 ;; 1. Primitive Datatypes and Operators
63 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
64
65 ;;; Numbers
66 9999999999999999999999 ; integers
67 #b111                  ; binary => 7
68 #o111                  ; octal => 73
69 #x111                  ; hexadecimal => 273
70 3.14                   ; reals
71 6.02e+23
72 1/2                    ; rationals
73 1+2i                   ; complex numbers
74
75 ;; Function application is written (f x y z ...)
76 ;; where f is a function and x, y, z, ... are operands
77 ;; If you want to create a literal list of data, use ' to stop it from
78 ;; being evaluated
79 '(+ 1 2) ; => (+ 1 2)
80 ;; Now, some arithmetic operations
81 (+ 1 1)  ; => 2
82 (- 8 1)  ; => 7
83 (* 10 2) ; => 20
84 (expt 2 3) ; => 8
85 (quotient 5 2) ; => 2
86 (remainder 5 2) ; => 1
87 (/ 35 5) ; => 7
88 (/ 1 3) ; => 1/3
89 (exact->inexact 1/3) ; => 0.3333333333333333
90 (+ 1+2i  2-3i) ; => 3-1i
91
92 ;;; Booleans
93 #t ; for true
94 #f ; for false -- any value other than #f is true
95 (not #t) ; => #f
96 (and 0 #f (error "doesn't get here")) ; => #f
97 (or #f 0 (error "doesn't get here"))  ; => 0
98
99 ;;; Characters
100 #\A ; => #\A
101 #\λ ; => #\λ
102 #\u03BB ; => #\λ
103
104 ;;; Strings are fixed-length array of characters.
105 "Hello, world!"
106 "Benjamin \"Bugsy\" Siegel"   ; backslash is an escaping character
107 "Foo\tbar\41\x21\u0021\a\r\n" ; includes C escapes, Unicode
108
109 ;; Strings can be added too!
110 (string-append "Hello " "world!") ; => "Hello world!"
111
112 ;; A string can be treated like a list of characters
113 (string-ref "Apple" 0) ; => #\A
114
115 ;; format can be used to format strings:
116 (format #t "~a can be ~a" "strings" "formatted")
117 ;; ==> print "strings can be formatted" on screen
118 (define str (format #f "~a can be ~a" "strings" "formatted"))
119 ;; str was assigned to "strings can be formatted"
120
121 ;; Printing is pretty easy
122 (display "I'm Guile. Nice to meet you!\n")
123
124 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
125 ;; 2. Variables
126 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
127 ;; You can create a variable using define
128 ;; a variable name can use any character except: ()[]{}",'`;#|\
129 (define some-var 5)
130 some-var ; => 5
131
132 ;; Accessing a previously unassigned variable is an exception
133 ; x ; => x: undefined ...
134
135 ;; Local binding: `me' is bound to "Bob" only within the (let ...)
136 (let ((me "Bob"))
137   "Alice"
138   me) 
139 ;; => "Bob"
140
141 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
142 ;; 3. Structs and Collections
143 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
144
145 ;; Record Type (Skip this chapter if you're trying web version
146 (use-modules (srfi srfi-9))
147 (define-record-type dog 
148   (make-dog name breed age)
149   dog?
150   (name dog-name)
151   (breed dog-breed)
152   (age dog-age))
153 (define my-pet
154   (make-dog "lassie" "collie" 5))
155 my-pet ; => #<dog>
156 (dog? my-pet) ; => #t
157 (dog-name my-pet) ; => "lassie"
158
159 ;;; Pairs (immutable)
160 ;; `cons' constructs pairs, `car' and `cdr' extract the first
161 ;; and second elements
162 (cons 1 2) ; => '(1 . 2)
163 (car (cons 1 2)) ; => 1
164 (cdr (cons 1 2)) ; => 2
165
166 ;;; Lists
167
168 ;; Lists are linked-list data structures, made of `cons' pairs and end
169 ;; with a `null' (or '()) to mark the end of the list
170 (cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3)
171 ;; `list' is a convenience variadic constructor for lists
172 (list 1 2 3) ; => '(1 2 3)
173 ;; and a quote can also be used for a literal list value
174 '(1 2 3) ; => '(1 2 3)
175
176 ;; Can still use `cons' to add an item to the beginning of a list
177 (cons 4 '(1 2 3)) ; => '(4 1 2 3)
178
179 ;; Use `append' to add lists together
180 (append '(1 2) '(3 4)) ; => '(1 2 3 4)
181
182 ;; Lists are a very basic type, so there is a *lot* of functionality for
183 ;; them, a few examples:
184 (map add1 '(1 2 3))          ; => '(2 3 4)
185 (map + '(1 2 3) '(10 20 30)) ; => '(11 22 33)
186 (filter even? '(1 2 3 4))    ; => '(2 4)
187 (count even? '(1 2 3 4))     ; => 2
188 (take '(1 2 3 4) 2)          ; => '(1 2)
189 (drop '(1 2 3 4) 2)          ; => '(3 4)
190
191 ;;; Vectors
192
193 ;; Vectors are fixed-length arrays
194 #(1 2 3) ; => '#(1 2 3)
195
196 ;; Use `vector-append' to add vectors together
197 (vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)
198
199 ;;; Hashes
200
201 ;; Create an immutable hash table (mutable example below)
202 ;; For GNU Guile
203 (define m (make-hash-table))
204 (hash-set! m 'a 1)
205 (hash-set! m 'b 2)
206 (hash-set! m 'c 3)
207
208 ;; Retrieve a value
209 (hash-ref m 'a) ; => 1
210
211 ;; Retrieving a non-present value is an exception
212 ; (hash-ref m 'd) => no value found
213
214 ;; You can provide a default value for missing keys
215 (hash-ref m 'd 0)
216 ;; => #f
217
218 ;; Use `hash-remove' to remove keys (functional too)
219 (hash-remove! m 'a) ; => ((b . 2) (c . 3))
220
221 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
222 ;; 3. Functions
223 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
224
225 ;; Use `lambda' to create functions.
226 ;; A function always returns the value of its last expression
227 (lambda () "Hello World") ; => #<procedure>
228
229 ;; Use parens to call all functions, including a lambda expression
230 ((lambda () "Hello World")) ; => "Hello World"
231 ((lambda (x) (+ x x)) 5)      ; => 10
232
233 ;; Assign a function to a var
234 (define hello-world (lambda () "Hello World"))
235 (hello-world) ; => "Hello World"
236
237 ;; You can shorten this using the function definition syntatcic sugae:
238 (define (hello-world2) "Hello World")
239
240 ;; The () in the above is the list of arguments for the function
241 (define hello
242   (lambda (name)
243     (string-append "Hello " name)))
244 (hello "Steve") ; => "Hello Steve"
245 ;; ... or equivalently, using a sugared definition:
246 (define (hello2 name)
247   (string-append "Hello " name))
248
249 ;; You can have multi-variadic functions too, using `case-lambda'
250 (define hello3
251   (case-lambda
252     (() "Hello World")
253     ((name) (string-append "Hello " name))))
254 (hello3 "Jake") ; => "Hello Jake"
255 (hello3) ; => "Hello World"
256 ;; ... or specify optional arguments with a default value expression
257 (define (hello4 (name "World"))
258   (string-append "Hello " name))
259
260 ;; Functions can pack extra arguments up in a list
261 (define (count-args . args)
262   (format #t "You passed ~a args: ~a" (length args) args))
263 (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)"
264 ;; ... or with the unsugared `lambda' form:
265 (define count-args2
266   (lambda args
267     (format #t "You passed ~a args: ~a" (length args) args)))
268
269 ;; You can mix regular and packed arguments
270 (define (hello-count name . args)
271   (format #t "Hello ~a, you passed ~a extra args" name (length args)))
272 (hello-count "Finn" 1 2 3)
273 ; => "Hello Finn, you passed 3 extra args"
274 ;; ... unsugared:
275 (define hello-count2
276   (lambda (name . args)
277     (format #t "Hello ~a, you passed ~a extra args" name (length args))))
278
279 ;; And with keywords
280 (define (hello-k #:name (name "World") #:greeting (g "Hello") . args)
281   (format #t "~a ~a, ~a extra args" g name (length args)))
282 (hello-k)                 ; => "Hello World, 0 extra args"
283 (hello-k 1 2 3)           ; => "Hello World, 3 extra args"
284 (hello-k #:greeting "Hi") ; => "Hi World, 0 extra args"
285 (hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args"
286 (hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6)
287                                          ; => "Hi Finn, 6 extra args"
288
289 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
290 ;; 4. Equality
291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
292
293 ;; for numbers use `='
294 (= 3 3.0) ; => #t
295 (= 2 1) ; => #f
296
297 ;; for object identity use `eq?'
298 (eq? 3 3) ; => #t
299 (eq? 3 3.0) ; => #f
300 (eq? (list 3) (list 3)) ; => #f
301
302 ;; for collections use `equal?'
303 (equal? (list 'a 'b) (list 'a 'b)) ; => #t
304 (equal? (list 'a 'b) (list 'b 'a)) ; => #f
305
306 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
307 ;; 5. Control Flow
308 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
309
310 ;;; Conditionals
311
312 (if #t               ; test expression
313     "this is true"   ; then expression
314     "this is false") ; else expression
315 ; => "this is true"
316
317 ;; In conditionals, all non-#f values are treated as true
318 (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo)
319 (if (member 'Groucho '(Harpo Groucho Zeppo))
320     'yep
321     'nope)
322 ; => 'yep
323
324 ;; `cond' chains a series of tests to select a result
325 (cond [(> 2 2) (error "wrong!")]
326       [(< 2 2) (error "wrong again!")]
327       [else 'ok]) ; => 'ok
328
329 ;;; Pattern Matching
330 (use-modules (ice-9 match)) ; use match module
331 (define (fizzbuzz? n)
332   (match (list (remainder n 3) (remainder n 5))
333     ((list 0 0) 'fizzbuzz)
334     ((list 0 _) 'fizz)
335     ((list _ 0) 'buzz)
336     (else #f)))
337
338 (fizzbuzz? 15) ; => 'fizzbuzz
339 (fizzbuzz? 37) ; => #f
340
341 ;;; Loops
342
343 ;; Looping can be done through (tail-) recursion
344 (define (lp i)
345   (when (< i 10)
346     (format #t "i=~a\n" i)
347     (lp (1+ i))))
348 (lp 5) ; => i=5, i=6, ...
349
350 ;; Similarly, with a named let
351 (let lp ((i 0))
352   (when (< i 10)
353     (format #t "i=~a\n" i)
354     (lp (1+ i)))) ; => i=0, i=1, ...
355
356 ;; how to get a range? just like range(0, 9)?
357 ;; the original 'iota' only accept one para
358 (iota 10) ; ==> (0 1 2 3 4 5 6 7 8 9)
359 ;; the 'iota' in srfi-1 was extended 
360 (use-modules (srfi srfi-1))
361 ;; #<procedure iota (count #:optional start step)>
362 (iota 5 10) ; => (10 11 12 13 14) 
363 ;; means from 10 count 5 times, each step +1 (plus one is default)
364 (iota 5 10 2) ; => (10 12 14 16 18)
365 ;; from 10 count 5 times, each step +2
366 ;; If you need a Python like range(5, 10) ==> (5 6 7 8 9), try:
367 (define (range from to) (map (lambda (x) (+ from x)) (iota (- to from))))
368 (range 5 10) ; => (5 6 7 8 9)
369
370 ;; how to do iteration?
371 (for-each display '(1 2 3 4 5))
372 ;; => 12345
373 (for-each (lambda (i) (format #t "i=~a\n" i))
374           (iota 10)) ; => i=0, i=1, ...
375 (for-each (lambda (i) (format #t "i=~a\n" i))
376           (range 5 10)) ; => i=5, i=6, ...
377
378 ;;; Iteration Over Other Sequences
379 ;; `for' allows iteration over many other kinds of sequences:
380 ;; lists, vectors, strings, sets, hash tables, etc...
381 (for-each display '(l i s t))
382 ;; => list
383 (define vector-for-each (@ (rnrs) vector-for-each))
384 ;; export vector-for-each from rnrs only
385 (vector-for-each display #(v e c t o r))
386 ;; => vector
387 (string-for-each display "string")
388 ;; => string
389 ;;; More Complex Iterations
390 ;; Parallel scan of multiple sequences (stops on shortest)
391 (do ((i 10) (j '(x y z) (cdr j))) 
392     ((null? j)) ; if j is '(), just end the loop
393   (format #t "~a:~a\n" i (car j)))
394 ; => 0:x 1:y 2:z
395
396 ;;; Exceptions
397
398 ;; To catch exceptions, use the 'catch' form
399 (catch 'my-error 
400   (lambda () (error 'my-error))
401   (lambda e (display "my error")))
402
403 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
404 ;; 6. Mutation
405 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
406
407 ;; Use `set!' to assign a new value to an existing variable
408 (define n 5)
409 (set! n (add1 n))
410 n ; => 6
411
412 ;; Use fluid for explicitly mutable values
413 (define n* (make-fluid 5))
414 (fluid-set! n* (add1 (fluid-ref n*)))
415 (fluid-ref n*) ; => 6
416
417 ;; Many Guile datatypes are immutable (pairs, lists, etc), some come in
418 ;; both mutable and immutable flavors (strings, vectors, hash tables,
419 ;; etc...)
420
421 ;; Use `vector' or `make-vector' to create mutable vectors
422 (define vec (vector 2 2 3 4))
423 (define wall (make-vector 100 'bottle-of-beer))
424 ;; Use vector-set! to update a slot
425 (vector-set! vec 0 1)
426 (vector-set! wall 99 'down)
427 vec ; => #(1 2 3 4)
428
429 ;; Create an empty mutable hash table and manipulate it
430 (define m3 (make-hash))
431 (hash-set! m3 'a 1)
432 (hash-set! m3 'b 2)
433 (hash-set! m3 'c 3)
434 (hash-ref m3 'a)   ; => 1
435 (hash-ref m3 'd 0) ; => 0
436 (hash-remove! m3 'a)
437
438 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
439 ;; 7. Modules
440 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
441
442 ;; Modules let you organize code into multiple files and reusable
443 ;; libraries; Make sure put all the module code in one file, since 
444 ;; the modules split as files. And the module name should be same 
445 ;; with the filename, say, module named (my-cake) is 'my-cake.scm',
446 ;; and module named (mods my-cake) is 'mods/my-cake.scm',
447 ;; (mods submods my-cake) ==> 'mods/submods/my-cake.scm'.
448 ;; ---begin my-cake.scm---
449 (define-module (my-cake) ; define a `cake' module based on racket/base
450   #:use-modules (ice-9 format) ; the pre-requisition of current module
451   #:export (print-cake)) ; function exported by the module
452
453   (define (show fmt n ch) ; internal function
454     (format #t fmt (make-string n ch))
455     (newline)))
456
457   (define (print-cake n)
458     (show "   ~a   " n #\.)
459     (show " .-~a-. " n #\|)
460     (show " | ~a | " n #\space)
461     (show "---~a---" n #\-))
462 ;; --end my-cake.scm---
463
464 ;; Be sure that the path of 'my-cake.scm' is in your current 
465 ;; %load-path list. Use `use-modules' to get all `provide'd names 
466 ;; from a module.
467 (use-modules (my-cake)) ; the ' is for a local submodule
468 (print-cake 3)
469 ; (show "~a" 1 #\A) ; => error, `show' was not exported
470
471 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
472 ;; 8. Classes and Objects
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
474 ;; TODO
475 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
476 ;; 9. Macros
477 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
478
479 ;; Macros let you extend the syntax of the language
480
481 ;; Let's add a while loop
482 (define-syntax-rule (while condition body ...)
483   (let loop ()
484     (when condition
485       body ...
486       (loop))))
487
488 (let ([i 0])
489   (while (< i  10)
490     (displayln i)
491     (set! i (add1 i))))
492
493 ;; Macros are hygienic, you cannot clobber existing variables!
494 (define-syntax-rule (swap! x y) ; -! is idomatic for mutation
495   (let ((tmp x))
496     (set! x y)
497     (set! y tmp)))
498
499 (define tmp 1)
500 (define a 2)
501 (define b 3)
502 (swap! a b)
503 (format #t "tmp = ~a; a = ~a; b = ~a\n" tmp a b) ; tmp is unaffected
504
505 ;; But they are still code transformations, for example:
506 (define-syntax-rule (bad-while condition body ...)
507   (when condition
508     body ...
509     (bad-while condition body ...)))
510 ;; this macro is broken: it generates infinite code, if you try to use
511 ;; it, the compiler will get in an infinite loop
512
513 </enscript>
514
515 Please read [[http://mitpress.mit.edu/sicp/full-text/book/book.html|SICP]] for more profound learning.
516
517 Happy Hacking!