public
Description: a Scheme written in Ruby, but implemented on the bus!
Homepage: http://bus-scheme.rubyforge.org
Clone URL: git://github.com/technomancy/bus-scheme.git
bus-scheme / tutorials / getting_started.html
100644 204 lines (170 sloc) 9.161 kb
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
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Getting Started with Bus Scheme</title>
  <style type='text/css'>
    body { font-family "Garuda", Sans; }
    tt { font-family: "Nimbus Mono L", Serif; background-color: #ddd; }
    pre { color: #222; font-family: "Nimbus Mono L", Serif; }
  </style>
</head>
<body>
 
<h2>Getting Started with Bus Scheme</h2>
<div id="index" style="width: 60em;">
 
<p>So a number of folks have asked me how they should get started with
Bus Scheme.[<a href='#fn1'>1</a>]. I've mostly just said silly things
like, \"Umm... good question. Maybe read/watch <a
href='http://mitpress.mit.edu/sicp/'>SICP</a>?\", which is silly
because it doesn't have much to do with the <i>Bus</i> part of Bus
Scheme, not because <i>The Structure and Interpretation of Computer
Programs</i> is silly.</p>
 
<p>There's a poster in <a href='http://www.powells.com/'>my favourite
bookstore</a> that has Dante's <i>Comedy</i>, the <i>Iliad</i>, and a
few other classics captioned with something like \"Might as well start
them now; you're going to have to read them eventually anyway.\" I hold
the same notion regarding SICP and perhaps <i>The Little Schemer</i>,
but I could see how it'd be helpful to have an introduction to Scheme
from a Rubyist's perspective since reading a book like that can be
large-ish mental investment.</p>
 
<p>Scheme is a programming language directly descended from Lisp. It's
most often compared to Common Lisp, which is in some senses its big
brother. Scheme is usually considered less \"kitchen-sink\"-ish than
Common Lisp in that it only defines an extremely clean small core
language and allows developers to extend it seamlessly to do what they
need. In the words of the creators of Scheme:</p>
 
<blockquote>
Programming languages should be designed not by piling feature on top
of feature, but by removing the weaknesses and restrictions that make
additional features appear necessary.  
</blockquote>
 
<p>(As a potential student of Scheme, you should be encouraged by this
notion as it directly translates into fewer concepts to learn.)</p>
 
<p>Ruby draws a lot of its heritage from Scheme, though Matz does not
share the idea that a language should be limited to a very small
number of core axioms from which everything else can be defined. [<a
href='#fn2'>2</a>] Destructive method names ending in \"!\" and
predicates ending in \"?\" were inspired by Scheme. Matz himself has
even lightheartedly referred to Ruby as \"MatzLisp\". So this is a
language that at the core should not feel too foreign to a Rubyist,
even if the syntax looks quite different.</p>
 
<p>Let's dive in. <tt>sudo gem install bus-scheme</tt> if you haven't
got it installed. Go ahead and launch Bus Scheme with the <tt>bus</tt>
executable. Like <tt>irb</tt>, it drops you into a REPL, or
Read-Eval-Print Loop. Scheme programs are made up of
<b>expressions</b>. When you enter expressions into the REPL, they get
evaluated and their value is shown. There are only a few simple rules
for how expressions get evaluated that we'll address below. Feel free
to experiment with entering expressions and seeing what gets
returned.</p>
 
<p>The simplest expressions are just <b>atoms</b>, which are simple
\"indivisible\" values, like symbols, numeric values, and strings. Some
atoms evaluate to themselves just like in Ruby, so entering
<tt>12</tt> into the REPL returns (and echoes) 12. <tt>\"foo\"</tt>
works the same way. Symbols are a little different. Ruby uses a colon
before the symbol's name, but in Scheme you refer to a symbol just
using its name. So <tt>baz</tt> refers to the symbol with the name
\"baz\". But if you enter <tt>baz</tt> into the REPL, Bus Scheme
complains:</p>
 
<pre class='code'>&gt; baz
Error: Undefined symbol: baz</pre>
 
<p>This is because symbols aren't considered <b>literals</b>; that is, they
don't evaluate to themselves like they do in Ruby. When Bus Scheme
encounters a symbol in this context, it treats it as a variable and
tries to return the value that's bound to it, which doesn't work when
it's not bound. So let's see what happens with a symbol that already
has a value bound to it:</p>
 
<pre class='code'>&gt; +
#&lt;Proc:0xb7c4b2a8@./bin/../lib/primitives.rb:16&gt;</pre>
 
<p>This is the way Bus Scheme represents a built-in (primitive)
<b>function</b>. In Scheme, functions are first-class values, so you
can bind them to variables, like you can with the <tt>lambda</tt>
keyword in Ruby. But in Scheme this the primary way you refer to
functions when you want to call them or pass them to other
functions.</p>
 
<p>Speaking of calling functions, it works something like this:</p>
 
<pre class='code'>&gt; (+ 3 4)
7</pre>
 
<p>This is a <b>list</b>, which is Scheme's compound expression. This list is
made up of three elements, in this case all atoms: the symbol
<tt>+</tt>, the number 3, and the number 4. In normal contexts, when
Scheme sees a list it treats it as a function call. First the first
item in the list is evaluated, which evaluates to a Ruby Proc
object. Then each of the remaining list elements are evaluated. Since
they're all literals here, they evaluate to themselves. Then the
arguments get passed to the function. Behind the scenes, this
translates rougly into <tt>Proc.new{|*args| args.sum}.call(3,
4)</tt>. Let's see something a bit more complicated:</p>
 
<pre class='code'>&gt; (+ (+ 1 2) (+ 3 4))
10</pre>
 
<p>In this case, the first <tt>+</tt> gets evaluated, and Bus Scheme sees
that it's a function. So it looks at its arguments: <tt>(+ 1 2)</tt>
gets evaluated to 3, and <tt>(+ 3 4)</tt> gets evaluated to 7. Then
those two arguments get passed to <tt>+</tt> and the result becomes
the value of the whole expression.
</p>
 
<p>That's the basics of how program execution happens, but you won't
get far without having a few more functions under your belt. Here are
a some to get you rolling:</p>
 
<dl>
  <dt>+, -, *, and /</dt>
  <dd>You've been introduced to + above, but I'm sure you recognize
  your other old friends from grade-school days. + and * support any
  number of arguments, but - and / take two. In regular Scheme these
  all only work for numerical types, but Bus Scheme borrows Ruby's
  methods and lets you pass strings and other objects to + and *.</dd>
 
  <dt>&lt;, &gt;, and =</dt>
  <dd>These are comparison functions. They work like they do in any
  language, but in Scheme you invoke them as <tt>(&gt; 3 7)</tt>
  etc. Again, Bus Scheme uses Ruby's underlying methods, so you can
  pass strings and other objects in, unlike in regular Scheme.</dd>
 
  <dt>list</dt>
  <dd>If you want a list of numbers, you may think you get this by
  entering <tt>(1 2 3)</tt>. The problem with this is that in normal
  contexts it gets treated like a function call, and it will complain
  that 1 is not a function. What you can do instead is <tt>(list 1 2
  3)</tt>, which evaluates to (1 2 3).</dd>
 
  <dt>map</dt>
  <dd>This works like Ruby's map, but it's a free-standing function
  instead of a method. So instead of <tt>[1, 2, 3].map {|x| x +
  3}</tt> you would do <tt>(map (lambda (x) (+ x 3)) (list 1 2
  3)</tt>, which would return <tt>(4 5 6)</tt>.</dd>
 
  <dt>substring</dt>
  <dd>Bus Scheme's <tt>(substring \"foobar\" 3 5)</tt> translates into
  <tt>\"foobar\"[3 .. 5]</tt> in Ruby.</dd>
 
  <dt>if</dt>
  <dd>The most basic conditional is <tt>if</tt>. Use it like this:
  <tt>(if x \"x is true\" \"x is false\")</tt>. <tt>if</tt> evaluates its
  first argument, which in this case is x. If it evaluates to a true
  value [<a href='#fn3'>3</a>] then its second argument gets evaluated
  and returned. If it's false then the remaining arguments (if any)
  are evaluated and the last one is returned.[<a
  href='#fn4'>4</a>]</dd>
</dl>
 
<p>Well, that's enough for now. You may not know enough to be
dangerous, but I hope you know enough to explore. Tune in next time
when I uncover the true Secrets of Lisp&trade; by explaining
<tt>cons</tt>, <tt>lambda</tt>, and special forms.</p>
 
<hr />
 
<p><a name='fn1'>1</a> - I didn't say it was a large number.</p>
 
<p><a name='fn2'>2</a> - I imagine this causes <a
href='http://blog.fallingsnow.net'>Evan</a> and <a
href='http://headius.blogspot.com/'>Charles</a> some varying amounts
of distress.</p>
 
<p><a name='fn3'>3</a> - In Scheme every value is true except
<tt>#f</tt>, which is equivalent to Ruby's <tt>false</tt>.</p>
 
<p><a name='fn4'>4</a> - Observant readers will note that this does
not follow the evaluation rule for functions given above which states
that every argument is evaluated before the function is called. This
is because <tt>if</tt> is not technically a function, but rather a
<b>special form</b>, and different rules apply for the evaluation of a
special form's arguments. There's more to this than I can cover in
this article, but these rules allow for great syntactic
flexibility.</p>
 
<hr />
 
<p>&copy; 2008 <a href='http://technomancy.us'>Phil
Hagelberg</a>.</p>
 
</div>
</body></html>