source: project/wiki/chicken-for-ruby-programmers

Last change on this file was 36916, checked in by sjamaan, 12 months ago

Add missing import in CHICKEN for Ruby programmers example

File size: 31.0 KB
Line 
1== CHICKEN for Ruby programmers
2
3[[toc:]]
4
5If you don't know much about CHICKEN yet, please take a moment to read
6the introductory part of [[/manual|The User's Manual]].  You're back?  Good!
7
8=== Paradigm independence
9
10The most important design feature of Ruby is that it is purely
11object-oriented; everything is an object.  Scheme is ''not'' an
12object-oriented language.  In fact, it does not commit to any
13particular programming paradigm -- it offers ''complete and total
14freedom to the programmer''.  If you decide (a part of) a program is
15best implemented in an object-oriented fashion, you can choose to use
16one of the many object systems.  Have a quick glance at the
17[[https://wiki.call-cc.org/chicken-projects/egg-index-5.html#oop|OOP category]] of
18the egg index to get an impression of the
19diversity of styles of object oriented programming you can use with
20CHICKEN.  By the way, the list on that page shows all the available
21''eggs'' for CHICKEN.  We'll explain all about these [[#Eggs|later]].
22
23Besides object-oriented programming, you can also program in a
24procedural fashion (like you would in Pascal, for example) or in a
25functional style (a bit like Haskell or ML) and you can even
26experiment with message-passing like in Erlang, logic programming
27like you would with Prolog, or stack languages like Forth and Factor.
28
29=== Origins
30
31Ruby's origins are firmly rooted in Lisp.  It takes many things and
32ideas from Lisp (symbols, lambdas, eval, metaprogramming, DSLs etc).
33What it doesn't take from Lisp it takes from Smalltalk, which was
34itself inspired by Lisp's clean syntax.  All this means that once
35you're over the initial hump of grokking the syntax, you'll find
36yourself in pretty familiar territory.
37
38Originally Ruby began as an implementation-defined language.  That is,
39there was only one implementation (Matz's) and whatever that implementation
40did '''was''' the language spec.  Nowadays, Ruby
41has [[http://rubyspec.org/|rubyspec]], an attempt to
42standardize the Ruby language.
43
44Likewise, Scheme is a specification-defined language.  There
45is one official language specification which says what Scheme is and
46how it works.  CHICKEN is simply an implementation of that
47specification.  There is one thing that is important to know right
48now: The Scheme specification is ''extremely'' minimal in design.  It
49tries to define as few language constructs as possible, but these few
50should be so powerful that you will not need any more to make
51programs.  This results in an extremely small spec and a very elegant
52and clean language with very few rules to remember, which makes it
53easy to learn.
54
55However, in the real world you will need much more than just
56programming constructs, you need things to interact with the operating
57system, networking libraries, etc.  That's where the difference
58between Scheme and other languages comes in: Every implementation of
59Scheme defines the things it thinks are necessary to build real
60programs with.  Unfortunately, this means most Scheme programs are
61inherently not portable from one implementation to another, but it also means that Scheme implementations
62are free to experiment how they want and explore new language
63territory.  This gives each Scheme implementation its uniqueness.
64
65Fortunately, most Scheme implementations including CHICKEN are fairly portable to modern hardware architectures and operating systems.  You may or may not be able to port a CHICKEN program to another Scheme, but you can port it from Windows to Mac OS X or Linux, or from the 32-bit Intel 386 to the 64-bit SPARC architecture, because CHICKEN runs in all those environments.  Usually "porting" just means "running it on that system", because just like Ruby CHICKEN has procedures that are platform-independent, with multiple implementations where the platform itself differs.
66
67CHICKEN's power is in how it extends the Scheme standard.  It has a
68very comfortable interface to C that does not require you to touch a
69single line of C code in order to create bindings to existing C
70libraries, but it also gives you the freedom to embed CHICKEN in C
71code or C in CHICKEN code as you want.  It offers a TCP/IP networking
72layer, it has great POSIX interoperability so you can interact with
73the OS. And most importantly: It can compile Scheme code to very
74efficient C code which can itself be compiled to machine code, giving
75you the best of both worlds: a dynamic language which allows you to
76program in the flexible way you are used to with Ruby, but this can be
77compiled for maximum efficiency.
78
79== Syntax
80
81=== The basics
82
83The one thing that is most strikingly different between Ruby and
84Scheme is of course the syntax.  Ruby has an extremely baroque syntax
85that allows you many freedoms in how you would like to write down
86things. Scheme, on the other hand, has only one way in which to write
87a given expression.  Let's start by looking at an example.  First we
88start by firing up an {{irb}} session and typing a little program:
89
90  irb(main):001:0> # My first program
91  irb(main):002:0* [1, 2, 3, 4].map{|x| x + 1}
92  => [2, 3, 4, 5]
93  irb(main):003:0>
94
95Now, we fire up a {{csi}} (chicken scheme interpreter) session:
96
97  #;1> ; My first program
98  (map add1 (list 1 2 3 4))
99  (2 3 4 5)
100  #;2>
101 
102In Scheme, lists are delimited with parentheses with its elements
103separated by spaces. As we can see, everything in Scheme is a list,
104even the expressions that you use to tell it what to do!  An
105expression in Scheme is always a list with the operator on its first
106position and the operands following it.  Procedures that accept no
107arguments are simply a list with only the procedure in it, for example
108{{(newline)}}, which simply displays a newline character.
109
110This simple rule also means that ''every parenthesis has a meaning''.
111You can't add more parentheses or leave off parentheses like you can
112in most Ruby expressions.  Adding extra parentheses simply applies
113the resulting expression as if it were a procedure:
114
115  #;2> ((newline))
116 
117  Error: call of non-procedure: #<unspecified>
118 
119          Call history:
120 
121          <syntax>                ((newline))
122          <syntax>                (newline)
123          <eval>          ((newline))
124          <eval>          (newline)       <--
125
126If {{(newline)}} returned a procedure, it would be called.  But as it
127happens, {{newline}} simply returns an unspecified value which is not
128a procedure and thus can't be applied.  We can also use the result of
129calling a procedure in the call to another procedure:
130
131  #;3> (add1 2)
132  3
133  #;4> (- 10 (add1 2) 1)
134  6
135
136We see that arithmetic is a little different from Ruby, as a result of
137the simple rules Scheme has for its syntax.  This may be a little
138awkward, especially with complex calculations:
139
140  #;5> (* (+ 1 (- 6 2) 2) (- 10 5))
141  35
142
143In Ruby (and other languages with algebraic syntax) this would have
144been
145
146  irb(main):002:0> (1 + (6 - 2) + 2) * (10 - 5)
147  => 35
148  irb(main):003:0> # Alternatively:
149  irb(main):004:0* (1 + 6 - 2 + 2) * (10 - 5)
150  irb(main):005:0> # or even:
151  irb(main):006:0* (((1) + ((((6 - 2)))) + 2) * (((10) - ((5)))))
152  => 35
153
154Both types of syntax have their advantages and disadvantages: The
155Ruby-like syntax is more natural, but you have to think about operator
156precedence rules.  CHICKEN does not need operator precedence rules
157because the precedence can be determined from the way it's nested, but
158it's less natural for most people (though you get used to it very
159quickly).
160
161Actually, right now you know almost all there is to know
162about Scheme's syntax!  CHICKEN has a couple of extensions to the
163basic Scheme syntax, but we won't go into detail here.  Later you'll
164see a couple of handy shortcuts, but this is basically it.
165
166=== Variables
167
168Variables are names for things.  CHICKEN has vary lax rules for
169naming variables.  Actually, ''any string'' is a valid identifier
170as long as you quote it correctly.
171
172Ruby:
173
174  #;1> x = 10
175  => 10
176  #;2> x
177  => 10
178  #;3> x-y-z = 10
179  NameError: undefined local variable or method `x' for main:Object
180        from (irb):2
181 
182Scheme:
183
184  #;1> (define x 10)
185  #;2> x
186  10
187  #;3> (define x-y-z 10)
188  #;4> x-y-z
189  10
190  #;5> (define %x% 1)
191  #;6> %x%
192  1
193  #;7> (define |a b c| 5)
194  #;8> |a b c|
195  5
196
197As you can see, because of Scheme's operator rules, symbols that would
198normally be separate tokens designating operators have no special
199meaning so we can use it in the middle of a name.  The convention in
200Scheme is to use the minus sign as word separator (in Ruby, you would
201use an underscore for separating words).  The final example shows how
202any string is allowed as a variable name: if the string contains
203syntax that would mean something else to Scheme you can enclose the
204variable name in pipe symbols.  The pipe symbol itself can be escaped
205with a backslash, if you need it to be part of a variable.
206
207To assign to a pre-existing variable we can also use {{set!}}:
208
209  #;1> (define x 10)
210  #;2> x
211  10
212  #;3> (set! x 20)
213  #;4> x
214  20
215
216Top-level variables can also be overwritten by simply redefining them,
217but in some cases you need {{set!}}.  However, set! is a typical
218artifact of an imperative programming style and in clean code you
219want to avoid using it.
220
221Scheme also allows the ''binding'' of local variables. Bound variables
222behave like the defined variables above, however, they are only valid
223within a local scope. The top-level variables we've seen are the equivalent
224of a global in Ruby.
225
226The most common binding constructs are {{let}} and {{let*}}.
227{{let}} allows for any number of bindings, none of which are related.
228
229<enscript highlight=scheme>
230(let ((a 5)
231      (b 10))
232  (+ a b))
233</enscript>
234
235{{let*}} is like let, except that the bindings are evaluated in order,
236so subsequent bindings can reference earlier bindings.
237
238<enscript highlight=scheme>
239(let* ((a 5)
240       (b (* 2 a)))
241  (+ a b))
242</enscript>
243
244There are other binding forms, such as {{letrec}} and the so-called
245''named let''. More information about these forms can be found in
246the [[http://schemers.org/Documents/Standards/R5RS/|Scheme specification]].
247
248=== Procedures
249
250Of course using simple expressions like this is not enough.  You'll
251need procedures too.  In Ruby, named procedures are actually methods
252on objects, but we can forget about that little detail for now:
253
254Ruby:
255
256<enscript highlight=ruby>
257def pythagoras(a, b)
258  Math.sqrt(a**2 + b**2)
259end
260</enscript>
261
262CHICKEN:
263
264<enscript highlight=scheme>
265(define pythagoras
266  (lambda (a b)
267    (sqrt (+ (* a a) (* b b)))))
268</enscript>
269
270Now that's interesting!  Procedures are just regular variables in
271Scheme (a bit like functions in Javascript).  We assign a lambda to it.
272We can do that in Ruby too, but it's not pretty:
273
274Ruby:
275  some_class.send(:define_method, :pythagoras) {|a, b| Math.sqrt(a**2 + b**2) }
276
277Just like in Ruby the {{def foo}} is shorter than the above, in Scheme
278we have a convenient shorthand for defining procedures too:
279
280<enscript highlight=scheme>
281  (define (pythagoras a b)
282    (sqrt (+ (* a a) (* b b))))
283</enscript>
284==== Recursion and tail-call optimization
285
286In Scheme, recursion is a very important tool.  In fact, it is so
287important that the Scheme standard ''demands'' tail call optimization
288(TCO), which basically means that you can have infinite recursion as
289long as the recursive procedure does not need to do anything after it
290returns.  That sounds a bit strange, so here's an example:
291
292Ruby:
293
294  irb(main):010:0> def add_up_to(num)
295  irb(main):011:1>   if num.zero?
296  irb(main):012:2>     0
297  irb(main):013:2>   else
298  irb(main):014:2*     add_up_to(num - 1) + num
299  irb(main):015:2>   end
300  irb(main):016:1> end
301  => nil
302  irb(main):017:0> add_up_to(4)
303  => 10
304  irb(main):018:0> add_up_to(9999)
305  SystemStackError: stack level too deep
306
307CHICKEN:
308
309  #;2> (define (add-up-to x)
310         (if (zero? x)
311             0
312             (+ (add-up-to (sub1 x)) x)))
313  #;3> (add-up-to 4)
314  10
315  #;4> (add-up-to 9999)
316  49995000
317
318Note the {{+}} in front of the {{(add-up-to (sub1 ...))}}. That is a cue that this is not tail-recursive code: each level of recursion must eventually come back 'up a level' in order to complete the addition, and so the program must keep a live reference to every level of recursion until the final result is computed.
319
320In most other Schemes, however, this will break just like in Ruby,
321because when the {{(+ (add-up-to (sub1 x)) x)}} expression is
322evaluated, the recursive call to {{add-up-to}} creates a new stack
323frame so that when it returns the x can be added to the result.
324
325[This code will 'break' in CHICKEN too, but only for much
326larger numbers. Although CHICKEN doesn't have an arbitrary stack
327depth, if you try (add-up-to) on a large enough number, you'll use up
328all your system memory before getting an answer. Read on for a better
329way to write it.]
330
331All Schemes know that when there is nothing that needs to be done
332after a procedure returns, there is no point in returning to the
333procedure that called it at all: instead it can just return directly
334to the procedure that called the current procedure. So the call can
335be optimized to become a ''goto'', replacing the current stack frame.
336
337Here is a tail-recursive version. Ruby still can't handle it:
338
339  irb(main):027:0> def add_up_to(x)
340  irb(main):028:1>   def inner(x, y)
341  irb(main):029:2>     if x.zero?
342  irb(main):030:3>       y
343  irb(main):031:3>     else
344  irb(main):032:3*       inner(x-1, x+y)
345  irb(main):033:3>     end
346  irb(main):034:2>   end
347  irb(main):035:1>   inner(x, 0)
348  irb(main):036:1> end
349  => nil
350  irb(main):037:0> add_up_to(9999)
351  SystemStackError: stack level too deep
352
353But Scheme can (this works in all Schemes):
354
355  #;2> (define (add-up-to x)
356         (define (inner x y)
357           (if (zero? x)
358               y
359               (inner (sub1 x) (+ y x))))
360         (inner x 0))
361  #;3> (add-up-to 4)
362  10
363  #;4> (add-up-to 9999)
364  49995000
365
366Note that the recursive call to {{inner}} isn't nested inside another function call, such as the {{(+ (add-up-to ...))}} in the first version. This is the hallmark of a tail-recursive program. (The astute reader might note that it actually *is* nested inside an {{(if ...)}} procedure, but conditional forms like {{if}} are handled intelligently in tail-recursion. The {{if}} statement itself is not nested inside a procedure call, so all is well.)
367
368As you'll notice, this version is a lot faster in CHICKEN too because
369it does not have to travel back through all those empty "stack
370frames".  In the first example, CHICKEN's memory usage increases upon
371every recursion: for large numbers, it will break because it can't
372allocate any more. But in the second example, memory usage will stay
373constant and simply loop forever.
374
375=== Blocks
376
377Ruby programmers will be familiar with ''blocks.'' Classic example in
378Ruby is the {{map}} method used to iterate over a collection, executing
379a ''block'' of code for each item in the collection.
380
381Ruby:
382  >> [1, 2, 3, 4, 5].map { |x| x * x }
383  => [1, 4, 9, 16, 25]
384
385Scheme also contains blocks, though we call them anonymous procedures
386usually. Procedures are created using the {{(lambda args body...)}} body
387form. This syntax is a little more verbose than Ruby's, but the trade off
388is that more than one procedure can be passed as an argument, whereas Ruby
389generally only allows one.
390
391Scheme:
392  #;1> (map (lambda (x) (* x x)) '(1 2 3 4 5))
393  (1 4 9 16 25)
394
395A more complicated example involves opening and closing files. Say we
396wanted to create a utility like {{wc -l}} that counts the number of
397lines in a file. In Ruby, it might look something like:
398
399<enscript highlight=ruby>
400puts IO.foreach("myfile").to_a.length
401</enscript>
402
403Similarly, Scheme uses anonymous procedures to create the same behavior:
404
405<enscript highlight=scheme>
406(with-input-from-file "myfile"
407  (lambda () (port-fold (lambda (line lines-so-far) (add1 lines-so-far)) 0 read-line)))
408</enscript>
409
410This Scheme code also showcases some typical functional style, using
411a ''fold'' operation instead of incrementing the value of a variable.
412
413
414== Data types
415
416Now we have a basic grasp of Scheme's syntax, we can have a look at the
417different data types CHICKEN has to offer.  We will do this from a Ruby
418perspective.
419
420=== Arrays
421
422In Ruby we use arrays for storing lists of things.  The obvious Scheme
423equivalent type is the list, you'd think.  This is sort of true:
424
425Ruby:
426
427<enscript highlight=ruby>
428x = [1, 2, 3, 4]
429x.map{|y| y + 10 }
430x.each{|y| puts y }
431</enscript>
432
433Scheme:
434
435<enscript highlight=scheme>
436(define x '(1 2 3))
437(map (lambda (x) (+ x 10)) x)
438(for-each print x)
439</enscript>
440
441Note that Scheme does not have the block scoping bug.  Another thing
442that we should note is the first line.  We create a list by
443''quoting'' it.  This allows us to enter the list in such a way that
444CHICKEN knows the list is just that; a list, and not a procedure
445application of the procedure called {{1}} on the arguments {{2}} and
446{{3}}.  The apostrophe takes care of that.
447
448However, we must always remember that the Scheme list is more like a
449linked list.  This means that it is very flexible in how we can add
450things to it and alter it, but it also means that traversing it takes
451more time as more items are added to it.  Accessing an element is an
452O(n) operation, where n is the position of the element.
453
454If we want O(1) operations on our lists, we can use a ''vector'':
455
456  #;1> (define x (vector 1 2 3 4))
457  #;2> (vector-ref x 2)
458  3
459  #;3> (define y (list 1 2 3 4))
460  #;4> (list-ref y 2)
461  3
462
463Adding new elements to a vector requires resizing or even copying the
464vector, just like it would in Ruby.  So whenever you're contemplating
465using a list type, think about the properties you want the list type
466to have.  This may sound odd, but in fact this gives you much more
467flexibility than Ruby, where you have the choice of using an Array,
468or... using an Array.  However, as Knuth famously said: "Premature
469optimization is the root of all evil", and you should probably take
470the list solution until it's proven that you ''need'' vectors.  Also,
471because Lisp was built on lists, it is very good at manipulating them,
472so they're most likely the most convenient datatype.
473
474CHICKEN also offers you several other types of array-like types, each
475with their own unique time and space properties.  Which you'll use
476depends on the task at hand and the situations your system will be
477used under.
478
479==== List procedures
480
481Lists are, as mentioned before, linked lists.  This means they always
482consist of two parts: a head and a tail.  We've seen the {{list}}
483procedure which creates lists, but this works on lower primitives:
484
485  #;1> (list 1)
486  (1)
487  #;2> (cons 1 '())
488  (1)
489
490The {{()}} is the empty list.  It is itself a list, but it is also a
491single symbol.  It serves as the ''end of list marker''.  That's why
492the list construction procedure, {{cons}}, can create longer lists too:
493
494  #;1> (list 1 2 3 4)
495  (1 2 3 4)
496  #;2> (cons 1 (cons 2 (cons 3 (cons 4 '()))))
497  (1 2 3 4)
498
499To take the head/tail of these lists we have two procedures:
500
501  #;1> (car '(1 2 3 4))
502  1
503  #;2> (cdr '(1 2 3 4))
504  (2 3 4)
505  #;3> (cdr (cdr '(1 2 3 4)))
506  (3 4)
507  #;4> (car (cdr (cdr '(1 2 3 4))))
508  3
509  #;5> (caddr '(1 2 3 4)) ; combination of car cdr cdr
510  3
511  #;6> (car (car '(1 2 3 4)))
512  Error: (car) bad argument type: 1
513  #;7> (cdr (cdr '(1)))
514  Error: (cdr) bad argument type: ()
515
516Actually, {{cons}} just sticks two things together, so we could also
517stick together two numbers:
518
519  #;1> (cons 1 2)
520  (1 . 2)
521  #;2> (car (cons 1 2))
522  1
523  #;3> (cdr (cons 1 2))
524  2
525
526Two things stuck together are called a ''pair''.  By sticking together
527more things without an end of list marker, we can create an ''improper
528list'':
529
530  #;1> (cons 1 (cons 2 (cons 3 4)))
531  (1 2 3 . 4)
532
533You should not use lists like these unless you know what you're doing,
534because ''all'' list library procedures expect ''proper lists'': lists
535with end markers.  CHICKEN supports the full
536[[http://srfi.schemers.org/srfi-1/srfi-1.html|SRFI-1]] out of the box.
537Have a look at that document and compare it to the Ruby standard
538Enumerator and Array methods.  Most of the procedures in srfi-1 will
539look ''very'' familiar to you.  Here are some examples:
540
541  $ chicken-install srfi-1
542  $ csi
543  #;1> (import srfi-1)  ;; Not needed in Ruby
544  ; loading library srfi-1 ...
545  #;2> ;; [1, 2, 3] + [4, 5, 6] / [1, 2, 3].concat([4, 5, 6])
546  (append '(1 2 3) '(4 5 6))
547  (1 2 3 4 5 6)
548  #;3> (map add1 '(1 2 3 4)) ;; [1, 2, 3, 4].map{|x| x + 1}
549  (2 3 4 5)
550  #;4> ;; No equivalent because map works on one object:
551  (map + '(1 2 3 4) '(5 6 7 8))
552  (6 8 10 12)
553  #;5> ;; [1, 2, 3, 4].each{|x| puts x}
554  (for-each (lambda (x) (printf "~A\n" x)) '(1 2 3 4))
555  1
556  2
557  3
558  4
559  #;6> ;; [1, 2, 3, 4, 5, 6].select{|x| x.even? }
560  (filter even? '(1 2 3 4 5 6))
561  (2 4 6)
562  #;7> (import (chicken string)) ;; To get the conc procedure
563  #;8> ;; [1, 2, 3, 4].inject(""){|str, x| str + x.to_s}
564  (fold (lambda (x str) (conc str x)) "" '(1 2 3 4))
565  "1234"
566
567=== Symbols
568
569Luckily, you are a Ruby programmer, so we will not have to go through
570the whole "explaining what symbols exactly are" again :)
571Actually, Ruby borrowed symbols from Lisp.
572
573Ruby:
574
575<enscript highlight=ruby>
576:foo
577"blah".to_sym
578:blah.to_s
579</enscript>
580
581Scheme:
582
583<enscript highlight=scheme>
584'foo
585(string->symbol "foo")
586(symbol->string 'foo)
587</enscript>
588
589As we can see, a symbol is only a quoted variable name!  This is the
590origin of symbols and also the reason you can {{send}} symbols
591representing method names to objects in Ruby.  Symbols have all the
592same semantics as Ruby's symbols: they can be compared in constant
593time and they take up very little memory space.
594
595=== Strings
596
597Strings are simple.  Just like in Ruby, we have strings enclosed by
598double quotes: {{"foo"}} works the same in Ruby as it does in CHICKEN.
599CHICKEN's double quoted strings work more like Ruby's single-quoted
600strings, though.  There is no string interpolation and other things;
601a string is just a string.
602
603Ruby:
604
605<enscript highlight=ruby>
606x = 10
607y = "x contains #{x}"
608z = "x contains " + x.to_s
609</enscript>
610
611Scheme:
612
613<enscript highlight=scheme>
614  (import (chicken string)) ;; To get the conc procedure
615  (define x 10)
616  (define y (sprintf "x contains ~A" x))
617  (define z (conc "x contains " x))
618  ; Conc automatically converts its arguments to strings. We also could do:
619  (define z (string-append "x contains " (->string x)))
620</enscript>
621
622Note that {{->string}} is simply the name of a procedure, including
623the arrow.
624
625It may be important to know that Scheme also has a ''character'' data
626type, just like Ruby:
627
628Ruby:
629
630  irb(main):001:0> "foo"[0]
631  => "f"
632
633  #;1> (string-ref "foo" 0)
634  #\f
635  #;2> (char->integer #\f)
636  102
637
638You will probably not need this data type for your first few Scheme
639programs so we won't go into it deeper here.
640
641==== String procedures
642
643CHICKEN comes shipped with
644[[http://srfi.schemers.org/srfi-13/srfi-13.html|SRFI-13]], which is a
645library of string procedures which is intended to be a lot like
646SRFI-1, which we already looked at [[#List procedures|a few sections
647ago]]:
648
649  $ chicken-install srfi-13
650  $ csi
651  #;1> (import srfi-13) ;; Not needed in Ruby
652  ; loading library srfi-13 ...
653  #;2> ;; "abc" + "def"
654  (string-append "abc" "def")
655  "abcdef"
656  #;3> ;; "abcdef"[-3..-1]
657  (string-take-right "abcdef" 2)
658  "ef"
659  #;4> ;; "abcdef".rjust(10)
660  (string-pad "abcdef" 10)
661  "    abcdef"
662  #;5> ;; ["this", "is", "very", "cool"].join(" ")
663  (string-join '("this" "is" "very" "cool"))
664  "this is very cool"
665  #;6> ;; "this is very cool".split(" ")
666  ;; NOT from srfi-13 but chicken's own (chicken string) module:
667  (string-split "this is very cool" " ")
668  ("this" "is" "very" "cool")
669
670=== Regular expressions
671
672Just like in Ruby, there's a Regex data type, but in CHICKEN there is
673no special syntax for it:
674
675Ruby:
676
677  irb(main):001:0> /(.)(.)(\d+)(\d)/.match("THX1138.").to_a
678  => ["HX1138", "H", "X", "113", "8"]
679
680CHICKEN:
681
682  #;1> (import (chicken irregex))
683  ; loading library chicken.irregex ...
684  #;2> (irregex-search "(.)(.)(\\d+)(\\d)" "THX1138.")
685  #<regexp-match>
686  #;3> (irregex-submatch #2 0)
687  "HX1138"
688  #;4> (irregex-submatch #2 1)
689  "H"
690
691The {{irregex-search}} procedure automatically transforms
692the first string to a regexp object.  You can also do that yourself:
693
694  #;3> (irregex-search (irregex "(.)(.)(\\d+)(\\d)") "THX1138.")
695
696The advantage of doing this is that when you need to match several
697strings you can use the same regexp so it doesn't have to precompile
698the regexp every time you call {{irregex-search}}.
699
700=== Hashes
701
702The final datatype we use a lot in Ruby is the Hash.  In CHICKEN there
703are two datatypes you could use instead of the Ruby Hash;
704''association lists'' (or ''alists'' for short) or ''hash tables''.
705
706==== Association Lists
707
708Association lists are the simpler Hash like structure in chicken.
709Effectively, alists are standard lists of ''pairs,'' where the
710first item in the pair is the key and the second item is the value.
711Consequently, alists have a nice literal form:
712
713<enscript highlight=scheme>
714'((foo  1) (bar 42) (baz 101))
715</enscript>
716
717To lookup a value in the alist, use {{assoc}}. For example to check
718if the pair {{(bar 42)}} is in the alist:
719
720  #;1> (assoc 'bar '((foo  1) (bar 42) (baz 101)))
721  (bar 42)
722
723If the pair is not in the list, you would get the boolean false ({{#f}}).
724If you need more stringent checks, you can also use {{assq}} or {{assv}},
725learning more about these procedures is an exercise for the reader.
726
727Alists may simplistic, and inquisitive readers may notice that lookup is
728{{O(n)}} time. However, they are convenient and adding new items is a constant
729time operation. You may find they work in may places that you might use a
730small Hash in Ruby.
731
732==== Hash tables
733
734For more complex hashing operations, CHICKEN supplies true hash tables.
735
736  $ chicken-install srfi-69
737  $ csi
738  #;1> (import srfi-69)
739  #;2> (define h (make-hash-table))
740  #;3> h
741  #<hash-table>
742  #;4> (hash-table-set! h 'foo 12)
743  12
744  #;5> (hash-table-set! h 'bar 101)
745  101
746  #;6> (hash-table-ref h 'bar)
747  101
748  #;7> (hash-table-delete! h 'bar)
749  #t
750  #;8> (hash-table-ref h 'bar)
751  Error: (hash-table-ref) hash-table does not contain key
752  bar
753
754Hash tables are more powerful overall, but do not offer convenient literal
755notation. If you need to convert from a hash table an alist you can use
756{{hash-table->alist}}. The {{alist->hash-table}} procedure converts in the
757opposite direction. For a complete list of supported procedures, check the
758[[/eggref/5/srfi-69|hash table]] add-on library docs.
759
760
761=== Booleans
762
763Scheme has a boolean type where {{#f}} is false and {{#t}} is true.
764Its handling of truthiness is a lot like Ruby's; anything that is not
765{{#f}} is treated as being ''true'':
766
767  #;1> (if #f
768           (print "WTF, it's true")
769           (print "It's not true"))
770  It's not true
771  #;2> (if #t
772           (print "Yes, it's really true")
773           (print "No, it's not true"))
774  Yes, it's really true
775  #;3> (if "Some random other value than #f"
776           (print "Yes, this is also true")
777           (print "No, it's not true"))
778  Yes, this is also true
779
780Ruby's {{nil}} does not have a direct equivalent in Scheme.  In the
781situations where a ''not present'' value is supposed to be returned,
782usually {{#f}} is used:
783
784  #;1> (import srfi-1)
785  ; loading library srfi-1 ...
786  #;2> (find even? '(3 1 4 1 5 9))
787  4
788  #;3> (find even? '(1 3 7 9))
789  #f
790
791In cases where a procedure really has no sensible thing to return, we
792use the special ''void'' value, returned by the {{void}} procedure:
793
794  #;1> (define (say-hello)
795         (print "Hello")
796         (void))
797  #;2> (say-hello)
798  Hello
799  #;3>
800
801As we see, the interpreter understands that there is no proper value
802to return so it displays the prompt immediately without showing the
803result value.  The example is a little contrived, because in real code
804we wouldn't explicitly call {{(void)}} because {{print}} already
805returns the {{void}} value.
806
807== Examples
808
809Now we have the tools to make programs, let's look at a few larger
810programs to better appreciate how one would program in CHICKEN.
811
812  TODO
813
814== CHICKEN and the Real World
815
816Programming is about more than having a pretty language, so let's look
817at what CHICKEN has to offer for real construction work.
818
819=== Eggs
820
821Eggs are to chicken what ''gems'' are to Ruby: installable extensions
822like libraries and programs.  The list of [[eggs]] is where you should
823look first when you are going to implement something big. You can
824install an egg almost like you install a gem, as follows:
825
826  $ chicken-install matchable
827
828This downloads and installs the egg with the name "matchable".  This
829egg has no dependencies, but if it did it would have downloaded and
830installed them as well.
831
832
833== Meta programming
834
835A hot topic in the Ruby community is meta programming and DSLs
836(Domain specific languages).  These ideas originated from Lisp, which
837means you can just keep on trucking in CHICKEN!
838
839=== Data is code and code is data
840
841The most fundamental concept of Lisp is that code is data.  As we've
842seen, procedure calls look like lists.  We've also seen that we can
843quote lists to "block" Scheme from interpreting a list as a procedure
844call.  We can also turn this around on its head and force a list to
845be evaluated as code:
846
847  #;1> (define calculate '(+ 1 2 3 4))
848  #;2> calculate
849  (+ 1 2 3 4)
850  #;3> (eval calculate)
851  10
852  #;4>
853
854"Big deal", you might say, "Ruby also has eval".  But the difference
855is what matters: In Ruby you have to construct strings to be evaluated,
856which means you need to be able to parse strings if you want to change
857a Ruby-program-stored-as-string.  In Scheme we can simply hack the
858list.  ''The program is stored in a parsed state'', so to speak.
859
860If we would want to change the operator from + to *, we can simply
861do that:
862
863  #;1> (eval (cons '* (cdr calculate)))
864  24
865
866This is much more robust than any regexp hacking or ad-hoc parsing on
867strings you want to evaluate.
868
869=== Macros
870
871One of the coolest concepts, but also the one most easily abused is
872''macros''.  Because Scheme stores code as data, you can change the
873code on-the-fly as described above.  You can do that at run-time on
874random data through eval, but you can also do it at compile-time on
875your program, which is usually the best time to do it.
876
877Scheme macros ''rewrite'' your code during compile time. They can
878range from simple to complex, with some macros defining entire
879"sublanguages" embedded in Scheme.
880
881Some people call Rails' {{acts_as_foo}} methods "macros". This
882description is not wrong, as these methods do ''rewrite'' your
883classes in a similar way to Scheme macros, but they are not quite
884as powerful.
885
886Here is a simple example of a task that is easy in Scheme, but
887much, much harder using Ruby's eval. Say you were debugging a
888program and found yourself printing out variables at certain
889points in the execution, along with the name of the variable
890so you could tell what you were looking at.
891
892<enscript highlight=scheme>
893  (print "myvar: " myvar)
894</enscript>
895
896You decide that repeatedly typing the variable name twice (once to
897indicate which variable, once to get the value) is a waste of time.
898Using a macro, you can quickly and easily abstract away the common
899syntax into one place.
900
901<enscript highlight=scheme>
902  (define-syntax ez-debug
903    (syntax-rules ()
904      ((_ var)
905       (print 'var ": " var))))
906   
907  (define myvar '(this is a list))
908 
909  (ez-debug myvar)
910</enscript>
911
912This simply wouldn't have been so easy with a regular procedure. By the time
913a procedure is called, syntactic information like variables names has
914been optimized away. If you are interested in a procedure like this in Ruby go to [[http://stackoverflow.com/questions/2603617/ruby-print-the-variable-name-and-then-its-value|http://stackoverflow.com/questions/2603617/ruby-print-the-variable-name-and-then-its-value]]
Note: See TracBrowser for help on using the repository browser.