CHICKEN is an implementation of Scheme programming language that can compile Scheme programs to C code as well as interpret them. CHICKEN supports R5RS and R7RS (work in progress) standards and many extensions.
1;; #!/usr/bin/env csi -s
2
3;; Run the CHICKEN REPL in the commandline as follows :
4;; $ csi
5
6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7; 0. Syntax
8;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
9
10;; Single line comments start with a semicolon
11
12#| Block comments
13 can span multiple lines and...
14 #| can be nested
15 |#
16|#
17
18;; S-expression comments are used to comment out expressions
19#; (display "nothing") ; discard this expression
20
21;; CHICKEN has two fundamental pieces of syntax: Atoms and S-expressions
22;; an atom is something that evaluates to itself
23;; all builtin data types viz. numbers, chars, booleans, strings etc. are atoms
24;; Furthermore an atom can be a symbol, an identifier, a keyword, a procedure
25;; or the empty list (also called null)
26'athing ;; => athing
27'+ ;; => +
28+ ;; => <procedure C_plus>
29
30;; S-expressions (short for symbolic expressions) consists of one or more atoms
31(quote +) ;; => + ; another way of writing '+
32(+ 1 2 3) ;; => 6 ; this S-expression evaluates to a function call
33'(+ 1 2 3) ;; => (+ 1 2 3) ; evaluates to a list
34
35
36;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
37; 1. Primitive Datatypes and Operators
38;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
39
40;; Numbers
4199999999999999999999 ;; integers
42#b1010 ;; binary ; => 10
43#o10 ;; octal ; => 8
44#x8ded ;; hexadecimal ; => 36333
453.14 ;; real
466.02e+23
473/4 ;; rational
48
49;;Characters and Strings
50#\A ;; A char
51"Hello, World!" ;; strings are fixed-length arrays of characters
52
53;; Booleans
54#t ;; true
55#f ;; false
56
57;; Function call is written as (f x y z ...)
58;; where f is a function and x,y,z, ... are arguments
59(print "Hello, World!") ;; => Hello, World!
60;; formatted output
61(printf "Hello, ~a.\n" "World") ;; => Hello, World.
62
63;; print commandline arguments
64(map print (command-line-arguments))
65
66(list 'foo 'bar 'baz) ;; => (foo bar baz)
67(string-append "pine" "apple") ;; => "pineapple"
68(string-ref "tapioca" 3) ;; => #\i;; character 'i' is at index 3
69(string->list "CHICKEN") ;; => (#\C #\H #\I #\C #\K #\E #\N)
70(string-intersperse '("1" "2") ":") ;; => "1:2"
71(string-split "1:2:3" ":") ;; => ("1" "2" "3")
72
73
74;; Predicates are special functions that return boolean values
75(atom? #t) ;; => #t
76
77(symbol? #t) ;; => #f
78
79(symbol? '+) ;; => #t
80
81(procedure? +) ;; => #t
82
83(pair? '(1 2)) ;; => #t
84
85(pair? '(1 2 . 3)) ;; => #t
86
87(pair? '()) ;; => #f
88
89(list? '()) ;; => #t
90
91
92;; Some arithmetic operations
93
94(+ 1 1) ;; => 2
95(- 8 1) ;; => 7
96(* 10 2) ;; => 20
97(expt 2 3) ;; => 8
98(remainder 5 2) ;; => 1
99(/ 35 5) ;; => 7
100(/ 1 3) ;; => 0.333333333333333
101
102;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
103; 2. Variables
104;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
105
106;; You can create variables with define
107;; A variable name can use any character except: ()[]{}",'`;#\
108(define myvar 5)
109myvar ;; => 5
110
111;; Alias to a procedure
112(define ** expt)
113(** 2 3) ;; => 8
114
115;; Accessing an undefined variable raises an exception
116s ;; => Error: unbound variable: s
117
118;; Local binding
119(let ((me "Bob"))
120 (print me)) ;; => Bob
121
122(print me) ;; => Error: unbound variable: me
123
124;; Assign a new value to previously defined variable
125(set! myvar 10)
126myvar ;; => 10
127
128
129;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
130; 3. Collections
131;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
132
133;; Pairs
134;; 'cons' constructs pairs,
135;; 'car' extracts the first element, 'cdr' extracts the rest of the elements
136(cons 'subject 'verb) ;; => '(subject . verb)
137(car (cons 'subject 'verb)) ;; => subject
138(cdr (cons 'subject 'verb)) ;; => verb
139
140;; Lists
141;; cons creates a new list if the second item is a list
142(cons 0 '()) ;; => (0)
143(cons 1 (cons 2 (cons 3 '()))) ;; => (1 2 3)
144;; 'list' is a convenience variadic constructor for lists
145(list 1 2 3) ;; => (1 2 3)
146
147
148;; Use 'append' to append lists together
149(append '(1 2) '(3 4)) ;; => (1 2 3 4)
150
151;; Some basic operations on lists
152(map add1 '(1 2 3)) ;; => (2 3 4)
153(reverse '(1 3 4 7)) ;; => (7 4 3 1)
154(sort '(11 22 33 44) >) ;; => (44 33 22 11)
155
156(define days '(SUN MON FRI))
157(list-ref days 1) ;; => MON
158(set! (list-ref days 1) 'TUE)
159days ;; => (SUN TUE FRI)
160
161;; Vectors
162;; Vectors are heterogeneous structures whose elements are indexed by integers
163;; A Vector typically occupies less space than a list of the same length
164;; Random access of an element in a vector is faster than in a list
165#(1 2 3) ;; => #(1 2 3) ;; literal syntax
166(vector 'a 'b 'c) ;; => #(a b c)
167(vector? #(1 2 3)) ;; => #t
168(vector-length #(1 (2) "a")) ;; => 3
169(vector-ref #(1 (2) (3 3)) 2);; => (3 3)
170
171(define vec #(1 2 3))
172(vector-set! vec 2 4)
173vec ;; => #(1 2 4)
174
175;; Vectors can be created from lists and vice-verca
176(vector->list #(1 2 4)) ;; => '(1 2 4)
177(list->vector '(a b c)) ;; => #(a b c)
178
179
180;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
181; 4. Functions
182;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
183
184;; Use 'lambda' to create functions.
185;; A function always returns the value of its last expression
186(lambda () "Hello World") ;; => #<procedure (?)>
187
188;; Use extra parens around function definition to execute
189((lambda () "Hello World")) ;; => Hello World ;; argument list is empty
190
191;; A function with an argument
192((lambda (x) (* x x)) 3) ;; => 9
193;; A function with two arguments
194((lambda (x y) (* x y)) 2 3) ;; => 6
195
196;; assign a function to a variable
197(define sqr (lambda (x) (* x x)))
198sqr ;; => #<procedure (sqr x)>
199(sqr 3) ;; => 9
200
201;; We can shorten this using the function definition syntactic sugar
202(define (sqr x) (* x x))
203(sqr 3) ;; => 9
204
205;; We can redefine existing procedures
206(foldl cons '() '(1 2 3 4 5)) ;; => (((((() . 1) . 2) . 3) . 4) . 5)
207(define (foldl func accu alist)
208 (if (null? alist)
209 accu
210 (foldl func (func (car alist) accu) (cdr alist))))
211
212(foldl cons '() '(1 2 3 4 5)) ;; => (5 4 3 2 1)
213
214
215;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
216; 5. Equality
217;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
218
219;; For numbers use '='
220(= 3 3.0) ;; => #t
221(= 2 1) ;; => #f
222
223;; 'eq?' returns #t if two arguments refer to the same object in memory
224;; In other words, it's a simple pointer comparison.
225(eq? '() '()) ;; => #t ;; there's only one empty list in memory
226(eq? (list 3) (list 3)) ;; => #f ;; not the same object
227(eq? 'yes 'yes) ;; => #t
228(eq? 3 3) ;; => #t ;; don't do this even if it works in this case
229(eq? 3 3.0) ;; => #f ;; it's better to use '=' for number comparisons
230(eq? "Hello" "Hello") ;; => #f
231
232;; 'eqv?' is same as 'eq?' all datatypes except numbers and characters
233(eqv? 3 3.0) ;; => #f
234(eqv? (expt 2 3) (expt 2 3)) ;; => #t
235(eqv? 'yes 'yes) ;; => #t
236
237;; 'equal?' recursively compares the contents of pairs, vectors, and strings,
238;; applying eqv? on other objects such as numbers and symbols.
239;; A rule of thumb is that objects are generally equal? if they print the same.
240
241(equal? '(1 2 3) '(1 2 3)) ;; => #t
242(equal? #(a b c) #(a b c)) ;; => #t
243(equal? 'a 'a) ;; => #t
244(equal? "abc" "abc") ;; => #t
245
246;; In Summary:
247;; eq? tests if objects are identical
248;; eqv? tests if objects are operationally equivalent
249;; equal? tests if objects have same structure and contents
250
251;; Comparing strings for equality
252(string=? "Hello" "Hello") ;; => #t
253
254
255;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
256; 6. Control Flow
257;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
258
259;; Conditionals
260(if #t ;; test expression
261 "True" ;; then expression
262 "False") ;; else expression
263 ;; => "True"
264
265(if (> 3 2)
266 "yes"
267 "no") ;; => "yes"
268
269;; In conditionals, all values that are not '#f' are treated as true.
270;; 0, '(), #() "" , are all true values
271(if 0
272 "0 is not false"
273 "0 is false") ;; => "0 is not false"
274
275;; 'cond' chains a series of tests and returns as soon as it encounters a true condition
276;; 'cond' can be used to simulate 'if/elseif/else' statements
277(cond ((> 2 2) "not true so don't return this")
278 ((< 2 5) "true, so return this")
279 (else "returning default")) ;; => "true, so return this"
280
281
282;; A case expression is evaluated as follows:
283;; The key is evaluated and compared with each datum in sense of 'eqv?',
284;; The corresponding clause in the matching datum is evaluated and returned as result
285(case (* 2 3) ;; the key is 6
286 ((2 3 5 7) 'prime) ;; datum 1
287 ((1 4 6 8) 'composite)) ;; datum 2; matched!
288 ;; => composite
289
290;; case with else clause
291(case (car '(c d))
292 ((a e i o u) 'vowel)
293 ((w y) 'semivowel)
294 (else 'consonant)) ;; => consonant
295
296;; Boolean expressions
297;; 'and' returns the first expression that evaluates to #f
298;; otherwise, it returns the result of the last expression
299(and #t #f (= 2 2.0)) ;; => #f
300(and (< 2 5) (> 2 0) "0 < 2 < 5") ;; => "0 < 2 < 5"
301
302;; 'or' returns the first expression that evaluates to #t
303;; otherwise the result of the last expression is returned
304(or #f #t #f) ;; => #t
305(or #f #f #f) ;; => #f
306
307;; 'when' is like 'if' without the else expression
308(when (positive? 5) "I'm positive") ;; => "I'm positive"
309
310;; 'unless' is equivalent to (when (not <test>) <expr>)
311(unless (null? '(1 2 3)) "not null") ;; => "not null"
312
313
314;; Loops
315;; loops can be created with the help of tail-recursions
316(define (loop count)
317 (unless (= count 0)
318 (print "hello")
319 (loop (sub1 count))))
320(loop 4) ;; => hello, hello ...
321
322;; Or with a named let
323(let loop ((i 0) (limit 5))
324 (when (< i limit)
325 (printf "i = ~a\n" i)
326 (loop (add1 i) limit))) ;; => i = 0, i = 1....
327
328;; 'do' is another iteration construct
329;; It initializes a set of variables and updates them in each iteration
330;; A final expression is evaluated after the exit condition is met
331(do ((x 0 (add1 x ))) ;; initialize x = 0 and add 1 in each iteration
332 ((= x 10) (print "done")) ;; exit condition and final expression
333 (print x)) ;; command to execute in each step
334 ;; => 0,1,2,3....9,done
335
336;; Iteration over lists
337(for-each (lambda (a) (print (* a a)))
338 '(3 5 7)) ;; => 9, 25, 49
339
340;; 'map' is like for-each but returns a list
341(map add1 '(11 22 33)) ;; => (12 23 34)
342
343
344;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
345; 7. Extensions
346;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
347
348;; The CHICKEN core is very minimal, but additional features are provided by library extensions known as Eggs.
349;; You can install Eggs with 'chicken-install <eggname>' command.
350
351;; complex numbers
3523+4i ;; => 3+2i
353;; Supports fractions without falling back to inexact flonums
3541/3 ;; => 1/3
355;; provides support for large integers through bignums
356(expt 9 20) ;; => 12157665459056928801
357;; And other 'extended' functions
358(log 10 (exp 1)) ;; => 2.30258509299405
359(numerator 2/3) ;; => 2
360
361;; 'utf8' provides unicode support
362(import utf8)
363"\u03BBx:(\u03BC\u0251.\u0251\u2192\u0251).xx" ;; => "λx:(μɑ.ɑ→ɑ).xx"
364
365;; 'posix' provides file I/O and lots of other services for unix-like operating systems
366;; Some of the functions are not available in Windows system,
367;; See http://wiki.call-cc.org/man/5/Module%20(chicken%20file%20posix) for more details
368
369;; Open a file to append, open "write only" and create file if it does not exist
370(define outfn (file-open "chicken-hen.txt" (+ open/append open/wronly open/creat)))
371;; write some text to the file
372(file-write outfn "Did chicken came before hen?")
373;; close the file
374(file-close outfn)
375;; Open the file "read only"
376(define infn (file-open "chicken-hen.txt" open/rdonly))
377;; read some text from the file
378(file-read infn 30) ;; => ("Did chicken came before hen? ", 28)
379(file-close infn)
380
381;; CHICKEN also supports SRFI (Scheme Requests For Implementation) extensions
382;; See 'http://srfi.schemers.org/srfi-implementers.html" to see srfi's supported by CHICKEN
383(import srfi-1) ;; list library
384(filter odd? '(1 2 3 4 5 6 7)) ;; => (1 3 5 7)
385(count even? '(1 2 3 4 5)) ;; => 2
386(take '(12 24 36 48 60) 3) ;; => (12 24 36)
387(drop '(12 24 36 48 60) 2) ;; => (36 48 60)
388(circular-list 'z 'q) ;; => z q z q ...
389
390(import srfi-13) ;; string library
391(string-reverse "pan") ;; => "nap"
392(string-index "Turkey" #\k) ;; => 3
393(string-every char-upper-case? "CHICKEN") ;; => #t
394(string-join '("foo" "bar" "baz") ":") ;; => "foo:bar:baz"
395
396
397;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
398; 8. Macros
399;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
400
401;; A 'for .. in ..' iteration like python, for lists
402(define-syntax for
403 (syntax-rules (in)
404 ((for elem in alist body ...)
405 (for-each (lambda (elem) body ...) alist))))
406
407(for x in '(2 4 8 16)
408 (print x)) ;; => 2, 4, 8, 16
409
410(for chr in (string->list "PENCHANT")
411 (print chr)) ;; => P, E, N, C, H, A, N, T
412
413;; While loop
414(define-syntax while
415 (syntax-rules ()
416 ((while cond body ...)
417 (let loop ()
418 (when cond
419 body ...
420 (loop))))))
421
422(let ((str "PENCHANT") (i 0))
423 (while (< i (string-length str)) ;; while (condition)
424 (print (string-ref str i)) ;; body
425 (set! i (add1 i))))
426 ;; => P, E, N, C, H, A, N, T
427
428;; Advanced Syntax-Rules Primer -> http://petrofsky.org/src/primer.txt
429;; Macro system in chicken -> http://lists.gnu.org/archive/html/chicken-users/2008-04/msg00013.html
430
431;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
432; 9. Modules
433;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
434
435;; Also See http://wiki.call-cc.org/man/5/Modules
436
437;; The 'test' module exports a value named 'hello' and a macro named 'greet'
438(module test (hello greet)
439 (import scheme)
440
441 (define-syntax greet
442 (syntax-rules ()
443 ((_ whom)
444 (begin
445 (display "Hello, ")
446 (display whom)
447 (display " !\n") ) ) ) )
448
449 (define (hello)
450 (greet "world") ) )
451
452;; we can define our modules in a separate file (say test.scm) and load them to the interpreter with
453;; (load "test.scm")
454
455;; import the module
456(import test)
457(hello) ;; => Hello, world !
458(greet "schemers") ;; => Hello, schemers !
459
460;; We can compile the module files in to shared libraries by using following command,
461;; csc -s test.scm
462;; (load "test.so")
463
464;; Functors
465;; Functors are high level modules that can be parameterized by other modules
466;; Following functor requires another module named 'M' that provides a function called 'multiply'
467;; The functor itself exports a generic function 'square'
468(functor (squaring-functor (M (multiply))) (square)
469 (import scheme M)
470 (define (square x) (multiply x x)))
471
472;; Module 'nums' can be passed as a parameter to 'squaring-functor'
473(module nums (multiply)
474 (import scheme) ;; predefined modules
475 (define (multiply x y) (* x y)))
476;; the final module can be imported and used in our program
477(module number-squarer = (squaring-functor nums))
478
479(import number-squarer)
480(square 3) ;; => 9
481
482;; We can instantiate the functor for other inputs
483;; Here's another example module that can be passed to squaring-functor
484(module stars (multiply)
485 (import chicken scheme) ;; chicken module for the 'use' keyword
486 (use srfi-1) ;; we can use external libraries in our module
487 (define (multiply x y)
488 (list-tabulate x (lambda _ (list-tabulate y (lambda _ '*))))))
489(module star-squarer = (squaring-functor stars))
490
491(import star-squarer)
492(square 3) ;; => ((* * *)(* * *)(* * *))