Previous: , Up: Introduction   [Contents][Index]


1.4 Tutorial

This tutorial will cover the basics of interpreting, compiling, and running Scheme programs from the command-line, the Guile REPL, and the web browser.

As a first step, Hoot’s built-in interpreter can be used from the command-line to evaluate simple Scheme expressions. To launch it, run hoot repl:

$ hoot repl
Hoot x.y.z

Enter `,help' for help.
(hoot user)>

Then evaluate some expressions:

(hoot user)> 42
=> 42
(hoot user)> (values 1 2 3)
=> 1
=> 2
=> 3
(hoot user)> (cons 'a 'b)
=> (a . b)
(hoot user)> (map 1+ '(1 2 3))
=> (2 3 4)
(hoot user)> (define (square x) (* x x))
(hoot user)> (square 4)
=> 16
(hoot user)> ,use (srfi srfi-1)
(hoot user)> (take '(a b c d) 3)
=> (a b c)
(hoot user)> ,quit

The hoot repl command runs a pre-built Wasm binary in NodeJS. That’s fun, but it’s even more fun to compile our own Scheme programs to Wasm. Let’s start with a simple program in a file called tutorial.scm:

(import (scheme base))
(list 'hoot 'hoot)

This program is written in R7RS-small Scheme. It can be compiled to Wasm and run with a single command:

guild compile-wasm --run tutorial.scm

If all went well, this will print the return value (hoot hoot). The --run flag is a handy way to quickly compile and test a small program using Hoot’s built-in Wasm interpreter.

Now, let’s take a look at how to use Hoot’s compilation API programmatically from the Guile REPL. Launch guile, import the (hoot compile) module and call the compile procedure.

scheme@(guile-user)> ,use (hoot compile)
scheme@(guile-user)> (define wasm
                       (compile '(list 'hoot 'hoot)
                                #:imports '((scheme base))))

The result is a Wasm module. There is a lot of stuff inside, but we’re not going to focus on that right now. We should load and run the module to verify that it outputs (hoot hoot) like we expect. We can do so from the comfort of our Guile REPL because Hoot includes a Wasm interpreter. There’s no need to use a web browser or other Wasm runtime to try out small programs.

First, import the (hoot reflect) module. Then, instantiate the Wasm module to boot up the interpreter:

scheme@(guile-user)> ,use (hoot reflect)
scheme@(guile-user)> (define instance (hoot-instantiate wasm))

All that’s left to do now is execute the program with hoot-load:

scheme@(guile-user)> (hoot-load instance)
$1 = #<hoot (hoot hoot)>

Ta-da! It feels kind of funny to compile a Scheme program to Wasm only to load it back into Scheme, but it’s a quick and easy way to test things out when guild compile-wasm --run doesn’t provide enough flexibility.

For cases when you simply want to compile an expression and see the result immediately, there is a faster method. Just use the compile-value procedure instead:

scheme@(guile-user)> (compile-value '(list 1 2 3))
$2 = #<hoot (1 2 3)>

With compile-value, the compiled Wasm module is thrown away, which is just fine for testing throwaway code.

Lists are cool but it would be a shame if we didn’t talk about compiling something a little more complicated. Let’s compile a simple, tail-recursive procedure! How about good ol’ factorial?

scheme@(guile-user)> (define hoot-factorial
                       (compile-value
                        '(let ()
                           (define (factorial x result)
                             (if (= x 1)
                                 result
                                 (factorial (- x 1)
                                            (* result x))))
                           factorial)))

A Hoot procedure can be called just like a regular procedure:

scheme@(guile-user)> (hoot-factorial 5 1)
$3 = 120

The Hoot reflection in Guile is great for quickly iterating on code, but what we really want is to get our programs running in a web browser. We’ve compiled a few things to Wasm now, but the resulting modules have stayed within the confines of Hoot’s Wasm interpreter. To make something that can be loaded by a web browser, we need to create a Wasm binary.

First, create a new directory for this tutorial:

mkdir hoot-tutorial
cd hoot-tutorial

Then, write the following trivial program to hello.scm:

(use-modules)

"Hello, world!"

Compile it and generate a bundle with all the necessary runtime libraries:

guild compile-wasm --bundle -o hello.wasm hello.scm

To run hello.wasm, we need to write a small JavaScript program to boot it up. Let’s call this hello.js:

async function load() {
  const [message] = await Scheme.load_main("hello.wasm");
  console.log(message);
}
window.addEventListener("load", load);

We also need a minimal index.html web page to bring it all together:

<!DOCTYPE html>
<html>
  <head>
    <script type="text/javascript" src="reflect.js"></script>
    <script type="text/javascript" src="hello.js"></script>
  </head>
  <body>
    Guile is a hoot!
  </body>
</html>

The file tree in hoot-tutorial should look like this:

./hello.js
./hello.scm
./hello.wasm
./index.html
./reflect.js
./reflect.wasm
./wtf8.wasm

Finally, we need a local web server to serve the files. Fortunately, Hoot includes a simple web server for development purposes. Start it like so:

hoot server

Visit http://localhost:8080 in your web browser. If all goes well, the text “Hello, world!” will be printed in the developer console.

We hope this tutorial has helped you get started with Hoot! Read on for full API documentation.


Previous: Installation, Up: Introduction   [Contents][Index]