Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

finished getting started tutorial

  • Loading branch information...
commit 49800752c336a4f0724f4be7df4efa2dd29e7783 1 parent b951316
@technomancy authored
View
4 README.txt
@@ -27,6 +27,10 @@ $ bus -e "(do some stuff)"
$ bus foo.scm # load a file
+== Tutorial
+
+See http://technomancy.us/104 for a "Getting Started" tutorial.
+
== What makes Bus Scheme different?
Well, for starters it's implemented on the bus. No other Scheme
View
2  lib/lambda.rb
@@ -10,7 +10,7 @@ class Lambda < Cons
def initialize(formals, body)
@formals, @body, @enclosing_scope = [formals, body, Lambda.scope]
@car = :lambda.sym
- @cdr = Cons.new(@formals, Cons.new(@body))
+ @cdr = Cons.new(@formals.sexp, Cons.new(@body.sexp))
end
# execute Lambda with given arg_values
View
2  lib/object_extensions.rb
@@ -27,6 +27,8 @@ class String
def sym
Sym.new(self)
end
+
+ alias_method :call, :[]
end
class Symbol
View
2  lib/scheme/core.scm
@@ -1,5 +1,5 @@
(define string->symbol
- (lambda (sym) (send sym 'intern)))
+ (lambda (sym) (send sym 'sym)))
(define substring
(lambda (string to from) (send string (quote []) to from)))
View
226 tutorials/getting_started.html
@@ -1,19 +1,33 @@
-<p>This is a DRAFT document. It's been posted for the purposes of
-getting feedback <b>only</b>. Please do not post the URL or
-copies/excerpts of this document in a public place.</p>
+<?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
+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
+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
@@ -21,7 +35,7 @@
<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
+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>
@@ -38,51 +52,77 @@
<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 jokingly 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>
+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. Like <tt>irb</tt>,
-running the <tt>bus</tt> executable drops you into a REPL, or
-Read-Eval-Print Loop. Feel free to experiment with entering values and
-seeing what gets returned.</p>
-
-<p>Scheme programs are made up of expressions. Each expression is
-either an atom or a list. Atoms 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>
+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 treated as literals; they don't
-evaluate to themselves. When Bus Scheme encounters a symbol in this
-context, it treats it as a variable and returns the value that's bound
-to it. So let's bind that sucker.</p>
-
-<pre class='code'>&gt; (define baz 12)
-baz</pre>
-
-<p>Now when Bus Scheme encounters the <tt>baz</tt> symbol it returns
-12, since that's the value the "baz" identifier is bound to in this
-context. But what's this we've just entered? That's actually a list
-made up of the symbol <tt>define</tt>, the symbol <tt>baz</tt>, and
-the literal numeric value 12. In normal contexts, a list is
-interpreted as a function call. TODO: explain function calls and
-evaluation rules more clearly. Scheme determines what function to call
-by evaluating the first element of the list. In this case, it's the
-symbol <tt>define</tt>, which evaluates to a built-in (primitive)
-function that binds its second argument to its first argument. Then it
-evaluates each of the arguments [<a href='#fn3'>3</a>] and passes
-those values to the function.</p>
+<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
@@ -90,49 +130,49 @@
<dl>
<dt>+, -, *, and /</dt>
- <dd>I'm sure you recognize your 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 to + and
- *.</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 returns a true value
- (in Scheme every value is true except <tt>#f</tt>, which is
- equivalent to Ruby's <tt>false</tt>) 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.</dd>
+ <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 it gets
- treated like a function call, and it will complain that 1 is not a
- function. (No joke, thanks for pointing that out.) What you can do
- instead is <tt>(list 1 2 3)</tt>.</dd>
-
- <dt>quote</dt>
- <dd>Remember when we entered the name of a symbol above and it
- returned the value that was bound to the symbol? If you really just
- want the symbol itself, you can pass it to quote: <tt>(quote
- baz)</tt> returns <tt>baz</tt>. You can also quote lists [<a
- href='#fn4'>4</a>] if you want their literal value returned instead
- of having them evaluated: <tt>(quote (define baz 12))</tt> returns
- <tt>(define baz 12)</tt>. Quote allows you to get around the way
- Scheme evaluates things to get at literal values.</dd>
+ 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 freestanding function
+ <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 &tm; by explaining
-<tt>cons</tt> and <tt>lambda</tt>.</p>
+when I uncover the true Secrets of Lisp&trade; by explaining
+<tt>cons</tt>, <tt>lambda</tt>, and special forms.</p>
<hr />
@@ -143,22 +183,22 @@
href='http://headius.blogspot.com/'>Charles</a> some varying amounts
of distress.</p>
-<p><a name='fn3'>3</a> - This isn't strictly true here;
-<tt>define</tt> is a special form, which means that not all its
-arguments get evaluated before they get passed to the function. This
-is why it works to pass <tt>define</tt> the symbol
-<tt>baz</tt>&mdash;it doesn't try to look up the value that
-<tt>baz</tt> is bound to. TODO: uh... too pedantic for a first
-article?</p>
-
-<p><a name='fn4'>4</a> - So what's the difference between
-<tt>list</tt> and <tt>quote</tt> then? Well, quote doesn't evaluate
-its arguments:</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><tt>(list 1 2 (+ 1 2))</tt> &rarr; <tt>(1 2 3)</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>
-<p><tt>(quote (1 2 (+ 1 2)))</tt> &rarr; <tt>(1 2 (+ 1 2))</tt></p>
+<hr />
<p>&copy; 2008 <a href='http://technomancy.us'>Phil
-Hagelberg</a>. Please send feedback to technomancy at google's mail
-service.</p>
+Hagelberg</a>.</p>
+
+</div>
+</body></html>
Please sign in to comment.
Something went wrong with that request. Please try again.