Tutorial.md @master — view markup · raw · history · blame
A Short Robin Tutorial
This document will lead you through writing a few simple Robin programs.
We will assume you've written some programs in a Lisp-like language such as Scheme or Racket or Irken. If you haven't, it will probably help a lot if you work through one of the many excellent tutorials available for these languages.
First, if you haven't done so, obtain a Robin interpreter for your
system. The README gives instructions for obtaining
and building the reference interpreter,
robin. We'll use it in
A Robin program is usually saved as a plain text file on your computer.
Open up a text editor, enter the following, and save it as
(display (subtract 50 42))
Now if you run the Robin interpreter on this file by typing, in your terminal:
You will see it display a number
which is the answer to the question, "What is 50 minus 42?".
In this small Robin program,
display is what's called a top-level form.
It's called this because it can only appear at the outermost level;
it can't be nested inside something. You can have multiple top-level
forms in a file, and Robin will try to do something with all of them.
You can edit your file to say
(define one 1) (display (subtract 8 one))
And if you run it again you will get the output
As of this version of Robin, there are only 4 kinds of top-level forms:
displayevaluates an expression and outputs the result.
defineevaluates an expression and assigns a name to it.
assertevaluates an expression and causes the interprter to abort with a message, if the expression does not evaluate to
reactorevaluates some expressions, creates a reactor based on them, and installs it.
Intrinsics vs. the Standard Library
Expressions in Robin are based on a very simple definition, in which there
are only 15 intrinsic operations.
subtract is one such intrinsic
add, by contrast, is not an intrinsic. If you create a program
(define one 1) (display (add 8 one))
and run it with
you'll get an error like
Main.hs: uncaught exception: (unbound-identifier add)
However, Robin does come with a standard library of operations, which are defined in terms of intrinsics. You need to tell Robin to load this standard library before you can use any of the operations in it. So, if you run,
bin/robin pkg/stdlib.robin sum.robin
You'll see the answer you probably expected,
Let's write a factorial function, and compute 5!.
(define fact (fun (self n) (multiply n (if (> n 1) (self self (subtract n 1)) 1)))) (display (fact fact 5))
multiply is not an intrinsic, so you'll need to run this with
bin/robin pkg/stdlib.robin fact.robin
Some of this definition is probably what you would expect from a recursive definition of factorial in any Lisp-like language. However, some of it is probably not.
It comes from the fact that Robin has no way to make a forward
reference — no
letrec or equivalent. At the time the definition
fact is being read, the
fact symbol is not yet defined,
fact cannot call itself directly.
So we give
fact a way to call itself by following a convention:
fact is called (including when
fact needs to call
fact function itself is passed as the first argument
fact. By convention we call this parameter
This is related to the so-called Y combinator.
Even though they are defined in Robin, parts of the Standard Library are often implemented in some other language. This is because their definition in Robin is intended to be correct and normative, not necessarily efficient. If the implementation of the operation in some other language has the same semantics as the Robin definition of the operation, it can be used interchangeably, and more efficiently.
In particular, the reference implementation exposes, by default, a set of "builtins" which map to the "small" subset of the standard library. You can turn them off with:
bin/robin --no-builtins pkg/stdlib.robin fact.robin
If you do this, you'll see
Main.hs: uncaught exception: (unbound-identifier fun)
You might conclude from this that
fun is not a built-in — and you'd
be right! Unlike basically every other Lisp-like language, in Robin,
fun is a derived form. It's implemented as a macro.
(To be written).
(To be written).