Gambit Scheme Pawns

Early draft

Some example might be broken, but should give a quick glimpse of the features of Gambit Scheme.

A pawn to rule them all

How to learn Gambit Scheme in 5 minutes?

So far, there is no crash course for Gambit Scheme. The following readings will help:

Reading the next questions will give you an overview of Gambit Scheme specifics.

How to start the REPL?

Use the gsi command to start the REPL:

% gsi
Gambit v4.9.3-1371-g1dbeaabd

> bytevector-u8-ref
#<procedure #2 u8vector-ref>
> (+ 40 2)
42
>
*** EOF again to exit

Hit twice Ctrl+D to exit the REPL.

How to run a program?

Create a file called for example main.scm with the following content:

#!
(import (scheme base))
(import (scheme process-context))


(define (first-command-line-argument)
  (cadr (command-line)))

(define (second-command-line-argument)
  (caddr (command-line)))

(display (+ (string->number (first-command-line-argument))
            (string->number (second-command-line-argument))))
(newline)

Mind the #! at the beginning of the file. Then run the following gsi command:

% gsi main.scm 40 2
42

How to compile a program to a binary?

Given the following program name main.scm:

#!
(import (scheme base))
(import (scheme process-context))


(define (first-command-line-argument)
  (cadr (command-line)))

(define (second-command-line-argument)
  (caddr (command-line)))

(display (+ (string->number (first-command-line-argument))
            (string->number (second-command-line-argument))))
(newline)

You can compile it to a native binary executable called main with the following command:

% gsc -exe main.scm

Then you can run the produced program with the following command:

% ./main 1331 6
1337

How to create a library?

In Scheme parlance, a library (also known as module) is a way to gather Scheme forms (procedures, macros or constants) inside a file, it is defined with four components:

Here is an example library called (mylib) inside a file called mylib.sld that exports a constant called magic:

(define-library (mylib)
  (export magic)
  (import (scheme base))

  (begin
    (define magic 42)))

Mind the begin that wraps the body of the library where magic is defined.

How to tell the interpreter or compiler to look for libraries in specific directories?

Both the interpreter gsi, and compiler gsc will take directories and source files as arguments. Such as gsi dir1/ dir2/ program.scm will look for libraries inside dir1/ and dir2/ and execute program.scm.

Mind the fact that the default behavior is to NOT look for libraries in the current working directory. To look for libraries in the current working directory you need to specify it in the command line, such as:

gsi . program.scm

Mind the the dot . that describe the current directory.

What is the recommended package manager?

Gambit is its own package manager, in the sense you can distribute and re-use libraries directly with gsi or gsc because if you allow Gambit, Gambit can install and run program relying on libraries from remote git repositories directly from the command line.

Here is an example program that will re-use the hello library:

#!
(import (scheme base))
(import (github.com/gambit/hello@1.0))

(hi "schemer!")

The github.com/gambit organization is in the default allowed list of URLs, so Gambit will download libraries from there without asking. Other URLs require your acknowledgement.

Gambit support any remote git repository as a source of libraries.

How to create and run tests?

Here is an example from the above hello library:

(define-library (github.com/gambit/hello test)

  (import (..))     ;; relative import of hello (preserves the version)
  (import (_test))  ;; for test-equal and test-error-tail
  (import (gambit)) ;; for lambda, with-output-to-string, and
                    ;; wrong-number-of-arguments-exception?

  (begin

    (test-equal "hello you!\n"
                (with-output-to-string (lambda () (hi "you"))))))

You can run the tests directly by passing the test.scm as argument of gsi such as:

% gsi test.scm

How to create a library that I want to distribute with git?

TODO

How to compile Scheme to JavaScript?

The easiest way to target JavaScript, nodejs or the browser, is via docker. The following script will compile Scheme to JavaScript the input FILENAME.scm into FILENAME.js:

#!/bin/sh
docker run -v $(pwd):/mnt --rm -it schemers/gambit:head gsc -:r7rs -target js -exe /mnt/$1
tail -n +2 $(basename $1 .scm) > "$(basename $1 .scm).js"
rm -f $(basename $1 .scm)

TODO: document limitations if any (macro support?)

How to call JavaScript from Scheme?

The easiest way to call JavaScript from Scheme is to use a Scheme Infix eXpression (SIX). Where the backslash \ change the reader syntax into infix notation, and the backtick allows to include scheme variables inside the infix expression. It works in a way that is similar to quasiquote and unquote:

(import (_six js))

(define magic 42)

\console.log(`magic)

Objects are automatically converted back and forth between Scheme and JavaScript. That behavior can be controlled with the JavaScript function foreign.

TODO: document type conversions

ref: https://zenodo.org/record/4711425

How to call Scheme from JavaScript?

TODO: Use javascript function foreign?

How to create a single .js file for a big Scheme project?

TODO: Use static compilation...

When targeting JavaScript, how to use fetch?

To do AJAX, also known as XHR, and under the new name fetch, you can do something such as the following:

\fetch("https://example.org").then(function(response) { return response.text() })

Mind the fact that the default behavior is to resolve JavaScript promises. Hence it will block the current Gambit thread. You might want do the call to fetch inside a dedicated Gambit thread, or wrap the promise with foreign.

How does the unverisal backend works?

What is Gambit Termite?

Gambit Termite is a library that provides an actor model similar to Erlang.

Can set! be used in code using Termite?

No.

Does Gambit support multicore?

Yes, but it is behind a configuration flag.

Is it possible to call or be called by C code?

Yes.

Is it cheap to use call/cc?

Yes!

What is Gambit threading model?

Gambit implement lightweight threads, also known as user-space threads that support non-blocking network input-output. Gambit threads are different from both green threads and POSIX threads.

Compared to green threads: Gambit threads are also cheap. Like green threads, Gambit threads will not block on network input or output. Unlike green threads, Gambit threads can be preempted because their priority became higher. Unlike most green thread approaches, Gambit threads do not require a special syntax such as yield, async or await to yield control, that is procedures are non-colored.

Compared to POSIX threads: Gambit threads are cheap. Gambit threads will not block on network input-output if you rely on builtin network procedures.

Gambit master includes behind a configuration flag, the ability to run Gambit threads on all cores. NB: Without multicore support, you need to rely on multiple Gambit processus to take advantage of multiple core, given it is easy to communicate data and code to a local or remote process, the ability to run on multiple cores, is merely an optimization.

Gambit threads are exposed with an interface very similar to POSIX threads. On top Gambit threads is implemented the actor model with the Termite library.

How does Termite compare to ConcurrentML?

It is equivalent [citation needed].

What macro system Gambit support?

Gambit support define-macro, and syntax-rule. Also, syntax-case is behind a configuration flag.

How to implement concurrency patterns such as provided by JavaScript Promise?

Use Gambit threads.