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

Last change on this file since 8726 was 8726, checked in by sjamaan, 12 years ago

Use print instead of (lambda (x) (display x) (newline))

File size: 24.4 KB
Line 
1[[toc:]]
2
3== Introduction
4
5If you don't know much about chicken yet, please take a moment to read
6the introductory part of [[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
17[[Eggs Unlimited 3#object-oriented-programming]] to get an impression of the
18diversity of styles of object oriented programming you can use with
19Chicken.  By the way, the list on that page shows all the available
20''eggs'' for Chicken.  We'll explain all about these [[#Eggs|later]].
21
22Besides object-oriented programming, you can also program in a
23procedural fashion (like you would in Pascal, for example) or in a
24functional style (a bit like Haskell or ML) and you can even
25experiment with message-passing like in Erlang, logic programming
26like you would with Prolog, or stack languages like Forth and Factor.
27
28=== Origins
29
30Ruby's origins are firmly rooted in Lisp.  It takes many things and
31ideas from Lisp (symbols, lambdas, eval, metaprogramming, DSLs etc).
32What it doesn't take from Lisp it takes from Smalltalk, which was
33itself inspired by Lisp's clean syntax.  All this means that once
34you're over the initial hump of grokking the syntax, you'll find
35yourself in pretty familiar territory.
36
37Originally, Ruby started out as an implementation-defined language.
38That is, there was only one implementation (Matz's) and whatever that
39implementation did '''was''' the language spec.  Nowadays, new
40implementations of Ruby are being developed, but as of this writing
41there is still no official specification on Ruby's syntax and
42semantics, by my knowledge.
43
44Scheme, on the other hand, 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 etcetera.  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 unportable, 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
65Chicken's power is in how it extends the Scheme standard.  It has a
66very comfortable interface to C that does not require you to touch a
67single line of C code in order to create bindings to existing C
68libraries, but it also gives you the freedom to embed Chicken in C
69code or C in Chicken code as you want.  It offers a TCP/IP networking
70layer, it has great POSIX interoperability so you can interact with
71the OS. And most importantly: It can compile Scheme code to very
72efficient C code which can itself be compiled to machine code, giving
73you the best of both worlds: a dynamic language which allows you to
74program in the flexible way you are used to with Ruby, but this can be
75compiled for maximum efficiency.
76
77== Syntax
78
79=== The basics
80
81The one thing that is most strikingly different between Ruby and
82Scheme is of course the syntax.  Ruby has an extremely baroque syntax
83that allows you many freedoms in how you would like to write down
84things. Scheme, on the other hand, has only one way in which to write
85a given expression.  Let's start by looking at an example.  First we
86start by firing up an {{irb}} session and typing a little program:
87
88  irb(main):001:0> # My first program
89  irb(main):002:0* [1, 2, 3, 4].map{|x| x + 1}
90  => [2, 3, 4, 5]
91  irb(main):003:0>
92
93Now, we fire up a {{csi}} (chicken scheme interpreter) session:
94
95  #;1> ; My first program
96  (map add1 (list 1 2 3 4))
97  (2 3 4 5)
98  #;2>
99 
100In Scheme, lists are delimited with parentheses with its elements
101separated by spaces. As we can see, everything in Scheme is a list,
102even the expressions that you use to tell it what to do!  An
103expression in Scheme is always a list with the operator on its first
104position and the operands following it.  Procedures that accept no
105arguments are simply a list with only the procedure in it, for example
106{{(newline)}}, which simply displays a newline character.
107
108This simple rule also means that ''every parenthesis has a meaning''.
109You can't add more parentheses or leave off parentheses like you can
110in most Ruby expressions.  Adding extra parentheses simply applies
111the resulting expression as if it were a procedure:
112
113  #;2> ((newline))
114
115  Error: call of non-procedure: #<unspecified>
116
117          Call history:
118
119          <syntax>                ((newline))
120          <syntax>                (newline)
121          <eval>          ((newline))
122          <eval>          (newline)       <--
123
124If {{(newline)}} returned a procedure, it would be called.  But as it
125happens, {{newline}} simply returns an unspecified value which is not
126a procedure and thus can't be applied.  We can also use the result of
127calling a procedure in the call to another procedure:
128
129  #;3> (add1 2)
130  3
131  #;4> (- 10 (add1 2) 1)
132  6
133
134We see that arithmetic is a little different from Ruby, as a result of
135the simple rules Scheme has for its syntax.  This may be a little
136awkward, especially with complex calculations:
137
138  #;5> (* (+ 1 (- 6 2) 2) (- 10 5))
139  35
140
141In Ruby (and other languages with algebraic syntax) this would have
142been
143
144  irb(main):002:0> (1 + (6 - 2) + 2) * (10 - 5)
145  => 35
146  irb(main):003:0> # Alternatively:
147  irb(main):004:0* (1 + 6 - 2 + 2) * (10 - 5)
148  irb(main):005:0> # or even:
149  irb(main):006:0* (((1) + ((((6 - 2)))) + 2) * (((10) - ((5)))))
150  => 35
151
152Both types of syntax have their advantages and disadvantages: The
153Ruby-like syntax is more natural, but you have to think about operator
154precedence rules.  Chicken does not need operator precedence rules
155because the precedence can be determined from the way it's nested, but
156it's less natural for most people (though you get used to it very
157quickly).
158
159Actually, right now you know almost all there is to know
160about Scheme's syntax!  Chicken has a couple of extensions to the
161basic Scheme syntax, but we won't go into detail here.  Later you'll
162see a couple of handy shorcuts, but this is basically it.
163
164=== Variables
165
166Variables are names for things.  Chicken has vary lax rules for
167naming variables.  Actually, ''any string'' is a valid identifier
168as long as you quote it correctly.
169
170Ruby:
171
172  #;1> x = 10
173  => 10
174  #;2> x
175  => 10
176  #;3> x-y-z = 10
177  NameError: undefined local variable or method `x' for main:Object
178        from (irb):2
179 
180Scheme:
181
182  #;1> (define x 10)
183  #;2> x
184  10
185  #;3> (define x-y-z 10)
186  #;4> x-y-z
187  10
188  #;5> (define %x% 1)
189  #;6> %x%
190  1
191  #;7> (define |a b c| 5)
192  #;8> |a b c|
193  5
194
195As you can see, because of Scheme's operator rules, symbols that would
196normally be separate tokens designating operators have no special
197meaning so we can use it in the middle of a name.  The convention in
198Scheme is to use the minus sign as word separator (in Ruby, you would
199use an underscore for separating words).  The final example shows how
200any string is allowed as a variable name: if the string contains
201syntax that would mean something else to Scheme you can enclose the
202variable name in pipe symbols.  The pipe symbol itself can be escaped
203with a backslash, if you need it to be part of a variable.
204
205To assign to a pre-existing variable we can also use {{set!}}:
206
207  #;1> (define x 10)
208  #;2> x
209  10
210  #;3> (set! x 20)
211  #;4> x
212  20
213
214Top-level variables can also be overwritten by simply redefining them,
215but in some cases you need {{set!}}.  However, set! is a typical
216artifact of an imperative programming style and in clean code you
217want to avoid using it.
218
219Scheme also allows the ''binding'' of local variables. Bound variables
220behave like the defined variables above, however, they are only valid
221within a local scope. The top-level variables we've seen are the equivalent
222of a global in Ruby.
223
224The most common binding constructs are {{let}} and {{let*}}.
225{{let}} allows for any number of bindings, none of which are related.
226
227<enscript highlight=scheme>
228  (let ((a 5)
229        (b 10))
230    (+ a b))
231</enscript>
232
233{{let*}} is like let, except that the bindings are evaluated in order,
234so subsequent bindings can reference earlier bindings.
235
236<enscript highlight=scheme>
237  (let* ((a 5)
238         (b (* 2 a)))
239    (+ a b))
240</enscript>
241
242There are other binding forms, such as {{letrec}} and the so-called
243''named let''. More information about these forms can be found in
244the [[http://schemers.org/Documents/Standards/R5RS/|Scheme specification]].
245
246=== Procedures
247
248Of course using simple expressions like this is not enough.  You'll
249need procedures too.  In Ruby, named procedures are actually methods
250on objects, but we can forget about that little detail for now:
251
252Ruby:
253
254<enscript highlight=ruby>
255  def pythagoras(a, b)
256    Math.sqrt(a**2 + b**2)
257  end
258</enscript>
259
260Chicken:
261
262<enscript highlight=scheme>
263  (define pythagoras
264    (lambda (a b)
265      (sqrt (* a a) (* b b))))
266</enscript>
267
268Now that's interesting!  Procedures are just regular variables in
269Scheme (a bit like functions in Javascript).  We assign a lambda to it.
270We can do that in Ruby too, but it's not pretty:
271
272Ruby:
273  some_class.send(:define_method, :pythagoras) {|a, b| Math.sqrt(a**2 + b**2) }
274
275Just like in Ruby the {{def foo}} is shorter than the above, in Scheme
276we have a convenient shorthand for defining procedures too:
277
278<enscript highlight=scheme>
279  (define (pythagoras a b)
280    (sqrt (* a a) (* b b)))
281</enscript>
282
283In Scheme, recursion is a very important tool.  In fact, it is so
284important that the Scheme standard ''demands'' tail call optimization
285(TCO), which basically means that you can have infinite recursion as
286long as the recursive procedure does not need to do anything after it
287returns.  That sounds a bit strange, so here's an example:
288
289Ruby:
290
291  irb(main):010:0> def add_up_to(num)
292  irb(main):011:1>   if num.zero?
293  irb(main):012:2>     0
294  irb(main):013:2>   else
295  irb(main):014:2*     add_up_to(num - 1) + num
296  irb(main):015:2>   end
297  irb(main):016:1> end
298  => nil
299  irb(main):017:0> add_up_to(4)
300  => 10
301  irb(main):018:0> add_up_to(9999)
302  SystemStackError: stack level too deep
303
304Chicken:
305
306  #;2> (define (add-up-to x)
307         (if (zero? x)
308             0
309             (+ (add-up-to (sub1 x)) x)))
310  #;3> (add-up-to 4)
311  10
312  #;4> (add-up-to 9999)
313  49995000
314
315In most other Schemes, however, this will break just like in Ruby,
316because when the {{(+ (add-up-to (sub1 x)) x)}} expression is
317evaluated, the recursive call to {{add-up-to}} creates a new stack
318frame so that when it returns the x can be added to the result.
319All Schemes know that when there is nothing that needs to be done
320after a procedure returns, there is no point in returning to the
321procedure that called it at all, instead it can just return directly
322to the procedure that called the current procedure, so the call can
323be optimized to become a ''goto'', replacing the current stack frame:
324
325Ruby still can't handle it:
326
327  irb(main):027:0> def add_up_to(x)
328  irb(main):028:1>   def inner(x, y)
329  irb(main):029:2>     if x.zero?
330  irb(main):030:3>       y
331  irb(main):031:3>     else
332  irb(main):032:3*       inner(x, x+y)
333  irb(main):033:3>     end
334  irb(main):034:2>   end
335  irb(main):035:1>   inner(x, 0)
336  irb(main):036:1> end
337  => nil
338  irb(main):037:0> add_up_to(9999)
339  SystemStackError: stack level too deep
340
341Scheme (this works in all Schemes):
342
343  #;2> (define (add-up-to x)
344         (define (inner x y)
345           (if (zero? x)
346               y
347               (inner (sub1 x) (+ y x))))
348         (inner x 0))
349  #;3> (add-up-to 4)
350  10
351  #;4> (add-up-to 9999)
352  49995000
353
354As you'll notice, this version is a lot faster in Chicken too because
355it does not have to travel back through all those empty "stack
356frames".  You can also notice the difference when you remove the stop
357condition and you look at your OS's process list.  Then Chicken's
358memory usage just keeps going up until it breaks because it can't
359allocate any more.  In the second example it will stay constant and
360simply loop forever.
361
362=== Blocks
363
364Ruby programmers will be familiar with ''blocks.'' Classic example in
365Ruby is the {{map}} method used to iterate over a collection, executing
366a ''block'' of code for each item in the collection.
367
368Ruby:
369  >> [1, 2, 3, 4, 5].map { |x| x * x }
370  => [1, 4, 9, 16, 25]
371
372Scheme also contains blocks, though we call them anonymous functions
373usually. Functions are created using the {{(lambda args body...)}} body
374form. This syntax is a little more verbose than Ruby's, but the trade off
375is that more than one function can be passed as an argument, whereas Ruby
376generally only allows one.
377
378Scheme:
379  #;1> (map (lambda (x) (* x x)) '(1 2 3 4 5))
380  (1 4 9 16 25)
381
382A more complicated example involves opening and closing files. Say we
383wanted to create a utility like {{wc -l}} that counts the number of
384lines in a file. In Ruby, it might look something like:
385
386<enscript highlight=ruby>
387  count = 0
388  File.open("myfile", 'r') { |fh|
389      count += 1 while fh.gets
390  }
391  puts count
392</enscript>
393
394Similarly, Scheme uses anonymous functions to create the same behavior:
395
396<enscript highlight=scheme>
397  (with-input-from-file "filename"
398    (lambda () (port-fold (lambda (line lines-so-far) (+ 1 lines-so-farc)) 0 read-line)))
399</enscript>
400
401This Scheme code also showcases some typical functional style, using
402a ''fold'' operation instead of incrementing the value of a variable.
403
404
405== Data types
406
407Now we have a basic grasp of Scheme's syntax, we can have a look at the
408different data types Chicken has to offer.  We will do this from a Ruby
409perspective.
410
411=== Arrays
412
413In Ruby we use arrays for storing lists of things.  The obvious Scheme
414equivalent type is the list, you'd think.  This is sort of true:
415
416Ruby:
417
418  x = [1, 2, 3, 4]
419  x.map{|y| x + 10 }
420  x.each{|y| puts y }
421
422Scheme:
423
424  (define x '(1 2 3))
425  (map x (lambda (x) (+ x 10)))
426  (for-each print x)
427
428Note that Scheme does not have the block scoping bug.  Another thing
429that we should note is the first line.  We create a list by
430''quoting'' it.  This allows us to enter the list in such a way that
431Chicken knows the list is just that; a list, and not a procedure
432application of the procedure called {{1}} on the arguments {{2}} and
433{{3}}.  The apostrophe takes care of that.
434
435However, we must always remember that the Scheme list is more like a
436linked list.  This means that it is very flexible in how we can add
437things to it and alter it, but it also means that traversing it takes
438more time as more items are added to it.  Accessing an element is an
439O(n) operation, where n is the position of the element.
440
441If we want O(1) operations on our lists, we can use a ''vector'':
442
443  #;1> (define x (vector 1 2 3 4))
444  #;2> (vector-ref x 2)
445  3
446  #;3> (define y (list 1 2 3 4))
447  #;4> (list-ref y 2)
448  3
449
450Adding new elements to a vector requires resizing or even copying the
451vector, just like it would in Ruby.  So whenever you're contemplating
452using a list type, think about the properties you want the list type
453to have.  This may sound odd, but in fact this gives you much more
454flexibility than Ruby, where you have the choice of using an Array,
455or... using an Array.  However, as Knuth famously said: "Premature
456optimization is the root of all evil", and you should probably take
457the list solution until it's proven that you ''need'' vectors.  Also,
458because Lisp was built on lists, it is very good at manipulating them,
459so they're most likely the most convenient datatype.
460
461Chicken also offers you several other types of array-like types, each
462with their own unique time and space properties.  Which you'll use
463depends on the task at hand and the situations your system will be
464used under.
465
466==== List procedures
467
468Lists are, as mentioned before, linked lists.  This means they always
469consist of two parts: a head and a tail.  We've seen the {{list}}
470procedure which creates lists, but this works on lower primitives:
471
472  #;1> (list 1)
473  (1)
474  #;2> (cons 1 '())
475  (1)
476
477The {{()}} is the empty list.  It is itself a list, but it is also a
478single symbol.  It serves as the ''end of list marker''.  That's why
479the list construction procedure, {{cons}}, can create longer lists too:
480
481  #;1> (list 1 2 3 4)
482  (1 2 3 4)
483  #;2> (cons 1 (cons 2 (cons 3 (cons 4 '()))))
484  (1 2 3 4)
485
486To take the head/tail of these lists we have two procedures:
487
488  #;1> (car '(1 2 3 4))
489  1
490  #;2> (cdr '(1 2 3 4))
491  (2 3 4)
492  #;3> (cdr (cdr '(1 2 3 4)))
493  (3 4)
494  #;4> (car (cdr (cdr '(1 2 3 4))))
495  3
496  #;5> (caddr '(1 2 3 4)) ; combination of car cdr cdr
497  3
498  #;6> (car (car '(1 2 3 4)))
499  Error: (car) bad argument type: 1
500  #;7> (cdr (cdr '(1)))
501  Error: (cdr) bad argument type: ()
502
503Actually, {{cons}} just sticks two things together, so we could also
504stick together two numbers:
505
506  #;1> (cons 1 2)
507  (1 . 2)
508  #;2> (car (cons 1 2))
509  1
510  #;3> (cdr (cons 1 2))
511  2
512
513Two things stuck together are called a ''pair''.  By sticking together
514more things without an end of list marker, we can create an ''improper
515list'':
516
517  #;1> (cons 1 (cons 2 (cons 3 4)))
518  (1 2 3 . 4)
519
520You should not use lists like these unless you know what you're doing,
521because ''all'' list library procedures expect ''proper lists'': lists
522with end markers.  Chicken supports the full
523[[http://srfi.schemers.org/srfi-1/srfi-1.html|SRFI-1]] out of the box.
524Have a look at that document and compare it to the Ruby standard
525Enumerator and Array methods.  Most of the procedures in srfi-1 will
526look ''very'' familiar to you.  Here are some examples:
527
528  #;1> (use srfi-1)  ;; Not needed in Ruby
529  ; loading library srfi-1 ...
530  #;2> ;; [1, 2, 3] + [4, 5, 6] / [1, 2, 3].concat([4, 5, 6])
531  (append '(1 2 3) '(4 5 6))
532  (1 2 3 4 5 6)
533  #;3> (map add1 '(1 2 3 4)) ;; [1, 2, 3, 4].map{|x| x + 1}
534  (2 3 4 5)
535  #;4> ;; No equivalent because map works on one object:
536  (map + '(1 2 3 4) '(5 6 7 8))
537  (6 8 10 12)
538  #;5> ;; [1, 2, 3, 4].each{|x| puts x}
539  (for-each (lambda (x) (printf "~A\n" x)) '(1 2 3 4))
540  1
541  2
542  3
543  4
544  #;6> ;; [1, 2, 3, 4, 5, 6].select{|x| (x % 2).zero? }
545  (filter even? '(1 2 3 4 5 6))
546  (2 4 6)
547  #;7> ;; [1, 2, 3, 4].inject(""){|str, x| str + x.to_s}
548  (fold (lambda (x str) (conc str x)) "" '(1 2 3 4))
549  "1234"
550
551=== Symbols
552
553Luckily, you are a Ruby programmer, so we will not have to go through
554the whole "explaining what symbols exactly are" again :)
555Actually, Ruby borrowed symbols from Lisp.
556
557Ruby:
558
559  :foo
560  "blah".to_sym
561  :blah.to_s
562
563Scheme:
564
565  'foo
566  (string->symbol "foo")
567  (symbol->string 'foo)
568
569As we can see, a symbol is only a quoted variable name!  This is the
570origin of symbols and also the reason you can {{send}} symbols
571representing method names to objects in Ruby.  Symbols have all the
572same semantics as Ruby's symbols: they can be compared in constant
573time and they take up very little memory space.
574
575=== Strings
576
577Strings are simple.  Just like in Ruby, we have strings enclosed by
578double quotes: {{"foo"}} works the same in Ruby as it does in Chicken.
579Chicken's double quoted strings work more like Ruby's single-quoted
580strings, though.  There is no string interpolation and other things;
581a string is just a string.
582
583Ruby:
584
585  x = 10
586  y = "x contains #{x}"
587  z = "x contains " + x.to_s
588
589Scheme:
590
591  (define x 10)
592  (define y (sprintf "x contains ~A" x))
593  (define z (conc "x contains " x))
594  ; Conc automatically converts its arguments to strings. We also could do:
595  (define z (string-append "x contains " (->string x)))
596
597Note that {{->string}} is simply the name of a procedure, including
598the arrow.
599
600It may be important to know that Scheme also has a ''character'' data
601type, unlike Ruby:
602
603Ruby:
604
605  irb(main):001:0> "foo"[0]
606  => 102
607
608  #;1> (string-ref "foo" 0)
609  #\f
610  #;2> (char->integer #\f)
611  102
612
613You will probably not need this data type for your first few Scheme
614programs so we won't go into it deeper here.
615
616==== String procedures
617
618Chicken comes shipped with
619[[http://srfi.schemers.org/srfi-13/srfi-13.html|SRFI-13]], which is a
620library of string procedures which is intended to be a lot like
621SRFI-1, which we already looked at [[#List procedures|a few sections
622ago]]:
623
624  #;1> (use srfi-13) ;; Not needed in Ruby
625  ; loading library srfi-13 ...
626  #;2> ;; "abc" + "def"
627  (string-append "abc" "def")
628  "abcdef"
629  #;3> ;; "abcdef"[-3..-1]
630  (string-take-right "abcdef" 2)
631  "ef"
632  #;4> ;; "abcdef".rjust(10)
633  (string-pad "abcdef" 10)
634  "    abcdef"
635  #;5> ;; ["this", "is", "very", "cool"].join(" ")
636  (string-join '("this" "is" "very" "cool"))
637  "this is very cool"
638  #;6> ;; "this is very cool".split(" ")
639  ;; NOT from srfi-13 but chicken's extras unit:
640  (string-split "this is very cool" " ")
641  ("this" "is" "very" "cool")
642
643=== Regular expressions
644
645Just like in Ruby, there's a Regex data type, but in Chicken there is
646no special syntax for it:
647
648Ruby:
649
650   m = /(.)(.)(\d+)(\d)/.match("THX1138.")
651   m[0]       #=> "HX1138"
652   m[1, 2]    #=> ["H", "X"]
653   m[1..3]    #=> ["H", "X", "113"]
654   m[-3, 2]   #=> ["X", "113"]
655
656Chicken:
657
658  #;1> (use regex)
659  ; loading library regex ...
660  #;2> (string-search "(.)(.)(\\d+)(\\d)" "THX1138.")
661  ("HX1138" "H" "X" "113" "8")
662
663The {{string-search}} procedure automatically transforms
664the first string to a regexp.  You can also do that yourself:
665
666  #;3> (string-search (regexp "(.)(.)(\\d+)(\\d)") "THX1138.")
667  ("HX1138" "H" "X" "113" "8")
668
669The advantage of doing this is that when you need to match several
670strings you can use the same regexp so it doesn't have to precompile
671the regexp every time you call {{string-search}}.
672
673=== Hashes
674
675The final datatype we use a lot in Ruby is the Hash.  In Chicken there
676are two datatypes you could use instead of the Ruby Hash;
677''association lists'' (or ''alists'' for short) or ''hash tables''.
678
679
680
681
682== Examples
683
684Now we have the tools to make programs, let's look at a few larger
685programs to better appreciate how one would program in Chicken.
686
687  TODO
688
689== Chicken and the Real World
690
691Programming is about more than having a pretty language, so let's look
692at what Chicken has to offer for real construction work.
693
694=== Eggs
695
696Eggs are to chicken what ''gems'' are to Ruby: installable extensions
697like libraries and programs.  The list of [[eggs]] is where you should
698look first when you are going to implement something big. You can
699install an egg almost like you install a gem, as follows:
700
701  $ chicken-setup runcmd
702
703This downloads and installs the egg with the name "runcmd".  This
704egg has no dependencies, but if it did it would have downloaded and
705installed them as well.
706
707
708== Meta programming
709
710A hot topic in the Ruby community is meta programming and DSLs
711(Domain specific languages).  These ideas originated from Lisp, which
712means you can just keep on trucking in Chicken!
713
714=== Data is code and code is data
715
716The most fundamental concept of Lisp is that code is data.  As we've
717seen, procedure calls look like lists.  We've also seen that we can
718quote lists to "block" Scheme from interpreting a list as a procedure
719call.  We can also turn this around on its head and force a list to
720be evaluated as code:
721
722  #;1> (define calculate '(+ 1 2 3 4))
723  #;2> calculate
724  (+ 1 2 3 4)
725  #;3> (eval calculate)
726  10
727  #;4>
728
729"Big deal", you might say, "Ruby also has eval".  But the difference
730is what matters: In Ruby you have to construct strings to be evaluated,
731which means you need to be able to parse strings if you want to change
732a Ruby-program-stored-as-string.  In Scheme we can simply hack the
733list.  ''The program is stored in a parsed state'', so to speak.
734
735If we would want to change the operator from + to *, we can simply
736do that:
737
738  #;1> (eval (cons '* (cdr calculate)))
739  24
740
741This is much more robust than any regexp hacking or ad-hoc parsing on
742strings you want to evaluate.
743
744=== Macros
745
746One of the coolest concepts, but also the one most easily abused is
747''macros''.  Because Scheme stores code as data, you can change the
748code on-the-fly as described above.  You can do that at run-time on
749random data through eval, but you can also do it at compile-time on
750your program, which is usually the best time to do it.
751
752  TODO
753
Note: See TracBrowser for help on using the repository browser.