CHICKEN

Личный сайт Go-разработчика из Казани

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) ;; => ((* * *)(* * *)(* * *))

Further Reading

Extra Info