summaryrefslogtreecommitdiffhomepage
path: root/chicken.html.markdown
blob: 37f6c8590ded0a626ff9b6cdb6ba3e764f3175fd (plain)
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
---
language: "CHICKEN"
filename: CHICKEN.scm
contributors:
  - ["Diwakar Wagle", "https://github.com/deewakar"]
---


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.


```scheme
;; #!/usr/bin/env csi -s

;; Run the CHICKEN REPL in the commandline as follows :
;; $ csi

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 0. Syntax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Single line comments start with a semicolon

#| Block comments
   can span multiple lines and...
   #| can be nested
   |#
|#

;; S-expression comments are used to comment out expressions
#; (display "nothing")    ; discard this expression 

;; CHICKEN has two fundamental pieces of syntax: Atoms and S-expressions
;; an atom is something that evaluates to itself
;; all builtin data types viz. numbers, chars, booleans, strings etc. are atoms
;; Furthermore an atom can be a symbol, an identifier, a keyword, a procedure
;; or the empty list (also called null)
'athing              ;; => athing 
'+                   ;; => + 
+                    ;; => <procedure C_plus>

;; S-expressions (short for symbolic expressions) consists of one or more atoms
(quote +)            ;; => + ; another way of writing '+
(+ 1 2 3)            ;; => 6 ; this S-expression evaluates to a function call
'(+ 1 2 3)           ;; => (+ 1 2 3) ; evaluates to a list 


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 1. Primitive Datatypes and Operators 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Numbers
99999999999999999999 ;; integers
#b1010               ;; binary ; => 10
#o10                 ;; octal  ; => 8
#x8ded               ;; hexadecimal ; => 36333
3.14                 ;; real
6.02e+23
3/4                  ;; rational

;;Characters and Strings
#\A                  ;; A char
"Hello, World!"      ;; strings are fixed-length arrays of characters

;; Booleans
#t                  ;; true
#f                  ;; false

;; Function call is written as (f x y z ...)
;; where f is a function and x,y,z, ... are arguments
(print "Hello, World!")    ;; => Hello, World!
;; formatted output
(printf "Hello, ~a.\n" "World")  ;; => Hello, World.

;; print commandline arguments
(map print (command-line-arguments)) 

(list 'foo 'bar 'baz)          ;; => (foo bar baz)
(string-append "pine" "apple") ;; => "pineapple"
(string-ref "tapioca" 3)       ;; => #\i;; character 'i' is at index 3
(string->list "CHICKEN")       ;; => (#\C #\H #\I #\C #\K #\E #\N)
(string-intersperse '("1" "2") ":") ;; => "1:2"
(string-split "1:2:3" ":")     ;; => ("1" "2" "3")


;; Predicates are special functions that return boolean values
(atom? #t)                ;; => #t

(symbol? #t)              ;; => #f

(symbol? '+)              ;; => #t

(procedure? +)            ;; => #t

(pair? '(1 2))            ;; => #t

(pair? '(1 2 . 3))        ;; => #t

(pair? '())               ;; => #f

(list? '())               ;; => #t


;; Some arithmetic operations

(+ 1 1)                   ;; => 2
(- 8 1)                   ;; => 7
(* 10 2)                  ;; => 20
(expt 2 3)                ;; => 8
(remainder 5 2)           ;; => 1
(/ 35 5)                  ;; => 7
(/ 1 3)                   ;; => 0.333333333333333

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 2. Variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; You can create variables with define
;; A variable name can use any character except: ()[]{}",'`;#\
(define myvar 5)
myvar        ;; => 5

;; Alias to a procedure
(define ** expt)
(** 2 3)     ;; => 8

;; Accessing an undefined variable raises an exception
s            ;; => Error: unbound variable: s

;; Local binding
(let ((me "Bob"))
  (print me))     ;; => Bob

(print me)        ;; => Error: unbound variable: me

;; Assign a new value to previously defined variable
(set! myvar 10) 
myvar             ;; => 10


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 3. Collections
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Pairs
;; 'cons' constructs pairs, 
;; 'car' extracts the first element, 'cdr' extracts the rest of the elements
(cons 'subject 'verb)       ;; => '(subject . verb)
(car (cons 'subject 'verb)) ;; => subject
(cdr (cons 'subject 'verb)) ;; => verb

;; Lists
;; cons creates a new list if the second item is a list
(cons 0 '())         ;; => (0)
(cons 1 (cons 2  (cons 3 '())))    ;; => (1 2 3)
;; 'list' is a convenience variadic constructor for lists
(list 1 2 3)    ;; => (1 2 3)


;; Use 'append' to append lists together
(append '(1 2) '(3 4)) ;; => (1 2 3 4)

;; Some basic operations on lists
(map add1 '(1 2 3))    ;; => (2 3 4)
(reverse '(1 3 4 7))   ;; => (7 4 3 1)
(sort '(11 22 33 44) >)   ;; => (44 33 22 11)

(define days '(SUN MON FRI))
(list-ref days 1)      ;; => MON
(set! (list-ref days 1) 'TUE)
days                   ;; => (SUN TUE FRI)

;; Vectors
;; Vectors are heterogeneous structures whose elements are indexed by integers
;; A Vector typically occupies less space than a list of the same length
;; Random access of an element in a vector is faster than in a list
#(1 2 3)                     ;; => #(1 2 3) ;; literal syntax
(vector 'a 'b 'c)            ;; => #(a b c) 
(vector? #(1 2 3))           ;; => #t
(vector-length #(1 (2) "a")) ;; => 3
(vector-ref #(1 (2) (3 3)) 2);; => (3 3)

(define vec #(1 2 3))
(vector-set! vec 2 4)
vec                         ;; => #(1 2 4)

;; Vectors can be created from lists and vice-verca
(vector->list #(1 2 4))     ;; => '(1 2 4)
(list->vector '(a b c))     ;; => #(a b c)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 4. Functions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Use 'lambda' to create functions.
;; A function always returns the value of its last expression
(lambda () "Hello World")   ;; => #<procedure (?)> 

;; Use extra parens around function definition to execute 
((lambda () "Hello World")) ;; => Hello World ;; argument list is empty

;; A function with an argument
((lambda (x) (* x x)) 3)           ;; => 9
;; A function with two arguments
((lambda (x y) (* x y)) 2 3)       ;; => 6

;; assign a function to a variable
(define sqr (lambda (x) (* x x)))
sqr                        ;; => #<procedure (sqr x)>
(sqr 3)                    ;; => 9

;; We can shorten this using the function definition syntactic sugar
(define (sqr x) (* x x))
(sqr 3)                    ;; => 9

;; We can redefine existing procedures
(foldl cons '() '(1 2 3 4 5)) ;; => (((((() . 1) . 2) . 3) . 4) . 5)
(define (foldl func accu alist)
  (if (null? alist)
    accu
    (foldl func (func (car alist) accu) (cdr alist))))

(foldl cons '() '(1 2 3 4 5))   ;; => (5 4 3 2 1)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 5. Equality
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; For numbers use '='
(= 3 3.0)                  ;; => #t
(= 2 1)                    ;; => #f

;; 'eq?' returns #t if two arguments refer to the same object in memory
;; In other words, it's a simple pointer comparison.
(eq? '() '())              ;; => #t ;; there's only one empty list in memory
(eq? (list 3) (list 3))    ;; => #f ;; not the same object
(eq? 'yes 'yes)            ;; => #t
(eq? 3 3)                  ;; => #t ;; don't do this even if it works in this case
(eq? 3 3.0)                ;; => #f ;; it's better to use '=' for number comparisons
(eq? "Hello" "Hello")      ;; => #f

;; 'eqv?' is same as 'eq?' all datatypes except numbers and characters
(eqv? 3 3.0)               ;; => #f
(eqv? (expt 2 3) (expt 2 3)) ;; => #t
(eqv? 'yes 'yes)           ;; => #t

;; 'equal?' recursively compares the contents of pairs, vectors, and strings,
;; applying eqv? on other objects such as numbers and symbols. 
;; A rule of thumb is that objects are generally equal? if they print the same.

(equal? '(1 2 3) '(1 2 3)) ;; => #t
(equal? #(a b c) #(a b c)) ;; => #t
(equal? 'a 'a)             ;; => #t
(equal? "abc" "abc")       ;; => #t

;; In Summary:
;; eq? tests if objects are identical
;; eqv? tests if objects are operationally equivalent
;; equal? tests if objects have same structure and contents

;; Comparing strings for equality
(string=? "Hello" "Hello") ;; => #t


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 6. Control Flow
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Conditionals
(if #t                     ;; test expression
  "True"                   ;; then expression
  "False")                 ;; else expression
                           ;; => "True"

(if (> 3 2)
  "yes"
  "no")                    ;; => "yes"

;; In conditionals, all values that are not '#f' are treated as true.
;; 0, '(), #() "" , are all true values
(if 0
  "0 is not false"
  "0 is false")            ;; => "0 is not false"

;; 'cond' chains a series of tests and returns as soon as it encounters a true condition
;; 'cond' can be used to simulate 'if/elseif/else' statements
(cond ((> 2 2) "not true so don't return this")
      ((< 2 5) "true, so return this")
      (else "returning default"))    ;; => "true, so return this"


;; A case expression is evaluated as follows:
;; The key is evaluated and compared with each datum in sense of 'eqv?',
;; The corresponding clause in the matching datum is evaluated and returned as result
(case (* 2 3)              ;; the key is 6
  ((2 3 5 7) 'prime)       ;; datum 1
  ((1 4 6 8) 'composite))  ;; datum 2; matched!
                           ;; => composite

;; case with else clause
(case (car '(c d))
  ((a e i o u) 'vowel)
  ((w y) 'semivowel)
  (else 'consonant))       ;; =>  consonant

;; Boolean expressions
;; 'and' returns the first expression that evaluates to #f
;; otherwise, it returns the result of the last expression
(and #t #f (= 2 2.0))                ;; => #f
(and (< 2 5) (> 2 0) "0 < 2 < 5")    ;; => "0 < 2 < 5"

;; 'or' returns the first expression that evaluates to #t 
;; otherwise the result of the last expression is returned
(or #f #t #f)                        ;; => #t
(or #f #f #f)                        ;; => #f

;; 'when' is like 'if' without the else expression
(when (positive? 5) "I'm positive")  ;; => "I'm positive"

;; 'unless' is equivalent to (when (not <test>) <expr>)
(unless (null? '(1 2 3)) "not null") ;; => "not null"


;; Loops
;; loops can be created with the help of tail-recursions
(define (loop count)
  (unless (= count 0)
    (print "hello") 
    (loop (sub1 count))))
(loop 4)                             ;; => hello, hello ...

;; Or with a named let
(let loop ((i 0) (limit 5))
  (when (< i limit)
    (printf "i = ~a\n" i)
    (loop (add1 i) limit)))          ;; => i = 0, i = 1....

;; 'do' is another iteration construct
;; It initializes a set of variables and updates them in each iteration
;; A final expression is evaluated after the exit condition is met
(do ((x 0 (add1 x )))            ;; initialize x = 0 and add 1 in each iteration
  ((= x 10) (print "done"))      ;; exit condition and final expression
  (print x))                     ;; command to execute in each step
                                 ;; => 0,1,2,3....9,done

;; Iteration over lists 
(for-each (lambda (a) (print (* a a)))
          '(3 5 7))                  ;; => 9, 25, 49

;; 'map' is like for-each but returns a list
(map add1 '(11 22 33))               ;; => (12 23 34)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 7. Extensions
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; The CHICKEN core is very minimal, but additional features are provided by library extensions known as Eggs.
;; You can install Eggs with 'chicken-install <eggname>' command.

;; complex numbers
3+4i                               ;; => 3+2i
;; Supports fractions without falling back to inexact flonums
1/3                                ;; => 1/3
;; provides support for large integers through bignums
(expt 9 20)                        ;; => 12157665459056928801 
;; And other 'extended' functions
(log 10 (exp 1))                   ;; => 2.30258509299405
(numerator 2/3)                    ;; => 2

;; 'utf8' provides unicode support
(import utf8)
"\u03BBx:(\u03BC\u0251.\u0251\u2192\u0251).xx" ;; => "λx:(μɑ.ɑ→ɑ).xx"

;; 'posix' provides file I/O and lots of other services for unix-like operating systems
;; Some of the functions are not available in Windows system,
;; See http://wiki.call-cc.org/man/5/Module%20(chicken%20file%20posix) for more details

;; Open a file to append, open "write only" and create file if it does not exist
(define outfn (file-open "chicken-hen.txt" (+ open/append open/wronly open/creat)))
;; write some text to the file
(file-write outfn "Did chicken came before hen?") 
;; close the file
(file-close outfn)
;; Open the file "read only"
(define infn (file-open "chicken-hen.txt" open/rdonly))
;; read some text from the file
(file-read infn 30)         ;; => ("Did chicken came before hen?  ", 28)
(file-close infn)

;; CHICKEN also supports SRFI (Scheme Requests For Implementation) extensions
;; See 'http://srfi.schemers.org/srfi-implementers.html" to see srfi's supported by CHICKEN
(import srfi-1)                    ;; list library
(filter odd? '(1 2 3 4 5 6 7))     ;; => (1 3 5 7)
(count even? '(1 2 3 4 5))         ;; => 2
(take '(12 24 36 48 60) 3)         ;; => (12 24 36)
(drop '(12 24 36 48 60) 2)         ;; => (36 48 60)
(circular-list 'z 'q)              ;; => z q z q ...

(import srfi-13)                   ;; string library
(string-reverse "pan")             ;; => "nap"
(string-index "Turkey" #\k)        ;; => 3
(string-every char-upper-case? "CHICKEN") ;; => #t
(string-join '("foo" "bar" "baz") ":")    ;; => "foo:bar:baz"


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 8. Macros
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; A 'for .. in ..' iteration like python, for lists
(define-syntax for
  (syntax-rules (in)
                ((for elem in alist body ...)
                 (for-each (lambda (elem) body ...) alist))))

(for x in '(2 4 8 16)
     (print x))          ;; => 2, 4, 8, 16

(for chr in (string->list "PENCHANT")
     (print chr))        ;; => P, E, N, C, H, A, N, T

;; While loop
(define-syntax while
  (syntax-rules ()
                ((while cond body ...)
                 (let loop ()
                   (when cond
                     body ...
                     (loop))))))

(let ((str "PENCHANT") (i 0))
  (while (< i (string-length str))     ;; while (condition)
         (print (string-ref str i))    ;; body 
         (set! i (add1 i))))           
                                       ;; => P, E, N, C, H, A, N, T

;; Advanced Syntax-Rules Primer -> http://petrofsky.org/src/primer.txt
;; Macro system in chicken -> http://lists.gnu.org/archive/html/chicken-users/2008-04/msg00013.html

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 9. Modules
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Also See http://wiki.call-cc.org/man/5/Modules

;; The 'test' module exports a value named 'hello' and a macro named 'greet'
(module test (hello greet)
  (import scheme)

  (define-syntax greet
    (syntax-rules ()
      ((_ whom) 
       (begin
         (display "Hello, ")
         (display whom)
         (display " !\n") ) ) ) )

  (define (hello)
    (greet "world") )  )

;; we can define our modules in a separate file (say test.scm) and load them to the interpreter with
;;         (load "test.scm")

;; import the module
(import test)
(hello)                ;; => Hello, world !
(greet "schemers")     ;; => Hello, schemers !

;; We can compile the module files in to shared libraries by using following command,
;;         csc -s test.scm
;;         (load "test.so")

;; Functors
;; Functors are high level modules that can be parameterized by other modules
;; Following functor requires another module named 'M' that provides a function called 'multiply'
;; The functor itself exports a generic function 'square'
(functor (squaring-functor (M (multiply))) (square)
         (import scheme M) 
         (define (square x) (multiply x x)))

;; Module 'nums' can be passed as a parameter to 'squaring-functor'
(module nums (multiply) 
        (import scheme)     ;; predefined modules
        (define (multiply x y) (* x y))) 
;; the final module can be imported and used in our program
(module number-squarer = (squaring-functor nums)) 

(import number-squarer)
(square 3)              ;; => 9

;; We can instantiate the functor for other inputs
;; Here's another example module that can be passed to squaring-functor
(module stars (multiply)
        (import chicken scheme)  ;; chicken module for the 'use' keyword
        (use srfi-1)             ;; we can use external libraries in our module
        (define (multiply x y)
          (list-tabulate x (lambda _ (list-tabulate y (lambda _ '*))))))
(module star-squarer = (squaring-functor stars))

(import star-squarer)
(square 3)              ;; => ((* * *)(* * *)(* * *))
```

## Further Reading
* [CHICKEN User's Manual](https://wiki.call-cc.org/manual).
* [R5RS standards](http://www.schemers.org/Documents/Standards/R5RS)


## Extra Info

* [For programmers of other languages](https://wiki.call-cc.org/chicken-for-programmers-of-other-languages)
* [Compare CHICKEN syntax with other languages](http://plr.sourceforge.net/cgi-bin/plr/launch.py)