Using iota
Table of Contents
1. Introduction
This is the user's guide. It assumes you know some Scheme and want to know what iota does with it. For a feature by feature comparison with the report, see R7RS-small coverage. For how the interpreter works inside, see How iota is put together.
2. The command line
iota # repl
iota program.iota a b # run a file. (command-line) => ("program.iota" "a" "b")
iota run program.iota # the same
iota eval '(* 6 7)' # evaluate one expression and print it
iota --version
iota --help
A script runs with every standard library imported. Its top level
forms are read and run one at a time, so a form can use what the
previous one defined and a syntax error is only reported when the
reader reaches it. The value of the last form is not printed. If you
want output, display it.
Options after the script name are passed to the script untouched, so
iota tool.iota --verbose works without a -- separator.
Exit status is 0 when the program finishes, 1 when it dies with an
uncaught error, and whatever (exit n) asked for otherwise. exit
runs the pending dynamic-wind after thunks first. emergency-exit
does not.
Errors in files are reported with the file name, line and column of the top level form they happened in:
$ iota bad.iota bad.iota:3:1: expected a pair, got: 1
Two environment variables matter. IOTA_LIBRARY_PATH is a colon
separated list of directories to search for library files, after the
directory of the importing file. IOTA_TAI_OFFSET overrides the
TAI minus UTC offset that current-second adds, for the day the
built in constant falls behind the leap second table.
Source files are read as UTF-8 whatever the locale says, and so are the standard streams.
3. Data types
3.1. Booleans
#t and #f, or #true and #false. Only #f is false. 0, """
and () are all true.
3.2. Numbers
Exact integers and rationals of any size, and inexact IEEE doubles:
iota> (+ 1/3 1/6) 1/2 iota> (expt 2 100) 1267650600228229401496703205376 iota> (* 2 3.5) 7.0 iota> (exact 0.5) 1/2
Radix prefixes work. #xff is 255, #b1010 is 10, #e1.5 is 3/2.
Complex numbers, in rectangular and polar notation:
iota> (* +i +i) -1 iota> (sqrt -4) +2i iota> (/ 1+2i 1-2i) -3/5+4/5i iota> (magnitude 3+4i) 5 iota> (make-polar 1 3.141592653589793) -1.0+1.2246467991473532e-16i
A complex number with exact parts stays exact. < and friends of
that kind only take real numbers, and so do abs, floor, max and
positive?.
3.3. Characters and strings
#\a, #\space, #\x41. Strings are mutable and take the full
escape set, including \n, \x41; and line continuations. String
literals, like every literal constant, are immutable.
(string-set! "abc" 0 #\z) is an error.
(string-set! (string-copy "abc") 0 #\z) is fine.
3.4. Symbols
Case sensitive. |two words| is a symbol with a space in it.
3.5. Pairs and lists
Mutable. A set-car! or set-cdr! is visible through every
reference to the pair.
3.6. Vectors and bytevectors
#(1 2 3) and #u8(0 255) literals, the full set of accessors,
utf8->string and string->utf8.
3.7. Records
(define-record-type point
(make-point x y)
point?
(x point-x set-point-x!)
(y point-y))
4. Control
Proper tail calls. (define (loop n) (if (= n 0) 'done (loop (- n 1))))
runs in constant space for any n.
call/cc works for early exits and for real coroutines, because
continuations can be re-entered:
(call/cc (lambda (return)
(for-each (lambda (x) (when (odd? x) (return x)))
'(2 4 5 6)))) ; => 5
(define (make-generator lst)
(define return #f)
(define resume #f)
(lambda ()
(call/cc (lambda (r)
(set! return r)
(if resume
(resume 'go)
(begin
(for-each (lambda (x)
(call/cc (lambda (k) (set! resume k) (return x))))
lst)
(return 'done)))))))
(define g (make-generator '(a b c)))
(list (g) (g) (g) (g)) ; => (a b c done)
The before and after thunks of dynamic-wind run on every entry and
exit, including re-entry through a continuation.
Exceptions:
(guard (e ((error-object? e) (error-object-message e)))
(error "boom" 1 2)) ; => "boom"
Parameters:
(define p (make-parameter 10))
(parameterize ((p 42)) (p)) ; => 42
(p) ; => 10
The current ports are parameters too, so redirecting output is
(parameterize ((current-output-port (open-output-string)))
(display "goes to the string port"))
and that is how the stdlib defines with-output-to-file.
eval and load:
(eval '(+ 1 2)) ; => 3
(eval '(+ 1 2) (interaction-environment))
(load "some-file.iota") ; into the current environment
5. Macros
syntax-rules:
(define-syntax my-or
(syntax-rules ()
((_) #f)
((_ e) e)
((_ e1 e2 ...) (let ((t e1)) (if t t (my-or e2 ...))))))
Expansion is hygienic. The t above cannot capture a t at the call
site, and if and let in the template mean what they meant where
the macro was defined, whatever the call site has rebound. Literals
such as else and => are matched by binding, so a locally rebound
else is only a variable.
6. Libraries
A program may start with import declarations, and the repl takes
them at any point. The repl and scripts begin with every standard
library imported, so (import (scheme base)) is optional there. It is
still what a portable program should write.
(define-library (my stack)
(import (scheme base))
(export make-stack push! pop!)
(begin
(define (make-stack) (list '*stack*))
(define (push! s x) (set-cdr! s (cons x (cdr s))))
(define (pop! s) (let ((x (cadr s))) (set-cdr! s (cddr s)) x))))
(import (prefix (my stack) stack:))
(define s (stack:make-stack))
A library the program does not define is looked for in my/stack.iota
next to the importing file, then in the directories
listed in IOTA_LIBRARY_PATH. Only exported names are visible.
only, except, prefix and rename work as in the report.
(environment '(scheme base)) gives eval an environment with those
bindings and nothing else.
7. The repl
| Command | Effect |
|---|---|
:help |
list the commands |
:ast EXPR |
show the parsed form |
:env [PREFIX] |
list bound names |
:load FILE |
run FILE in the current environment |
:q / :quit |
exit |
Tab completes over everything bound. History is kept in
~/.local/state/iota/history. Unbalanced input continues on the next
line.
8. The standard library
Compiled into the binary from lib/iota/stdlib.iota and loaded at
startup. The non-standard extras are in (iota extras), which the
repl imports by default. That library has foldl, foldr, unfold,
filter, remove, partition, any, every, compose, curry,
flip, displayln, print, string-join,
call-with-output-string, port->string, and fact and fib.