3. Running Larceny

Larceny can run in any of these distinct modes:

R5RS              traditional read/eval/print loop (the default)
R6RS              batch execution of R6RS top-level programs
R7RS              R7RS read/eval/print loop or batch execution
Scheme script     batch execution of R7RS/R6RS Scheme scripts

R5RS mode extends the Scheme language described by the R5RS and IEEE/ANSI Std 1178 by adding R7RS/R6RS lexical syntax and most of the procedures described by the newer R6RS and R7RS standards.

R6RS mode is largely redundant with Larceny's R7RS mode (because every reasonable R6RS library and program could just as well be executed in R7RS mode). There is only one difference between those two modes: R6RS mode enforces the R6RS mandates that, among other things, forbid read/eval/print loops and most extensions to R6RS lexical syntax.

R7RS mode will accept any combination of R7RS and R6RS libraries and programs. In Larceny, R6RS Scheme becomes a proper subset of R7RS Scheme.

Scheme scripts are directly executable R7RS/R6RS programs.

3.1. R5RS mode

When you start Larceny in R5RS mode (the default), you will be presented with a banner message and the read-eval-print loop's prompt:

    % larceny
    Larceny vX.Y "<version_name>" (MMM DD YYYY HH:MM:SS, ...)
    larceny.heap, built ...

    >

You can enter a Scheme expression at the prompt. After a complete expression has been read, it will be evaluated and its results printed.

Note

In native Larceny, the expression is evaluated by compiling it to native machine code, which is then executed. In Petit Larceny, the expression is evaluated by an interpreter because compiling to C, running the C compiler, and loading the compiled C code would take too long. Interpreted code behaves like compiled code, so most of what this manual says about the compiler is also true of Petit Larceny's interpreter.

3.2. R6RS mode

To execute a top-level R6RS program that is contained within a file named pgm, type:

    larceny -r6rs -program pgm

The -program option can be omitted, in which case Larceny will read the top-level program from standard input:

    larceny -r6rs < pgm

If you omit the -program option and do not redirect standard input, then Larceny will wait patiently for you to type a complete top-level program into standard input, terminating it with an end-of-file.

You probably don't want to do that. Had you wanted to type R6RS code at Larceny, you'd be using Larceny's R7RS read/eval/print loop instead.

3.3. R7RS mode

To execute a top-level R7RS/R6RS program that is contained within a file named pgm, type:

    larceny -r7rs -program pgm

To interact with Larceny's R7RS read/eval/print loop, omit the -program option:

    % larceny -r7rs
    Larceny v0.98 "General Ripper" (...)

The (scheme base) library has already been imported, but you may want to import other libraries as well. For example:

    > (import (scheme read)
              (scheme write)
              (scheme file)
              (scheme cxr)
              (scheme inexact)
              (scheme complex)
              (scheme char)
              (scheme load))

If you'd rather have Larceny import all of the standard R7RS and R6RS libraries at startup, along with a few Larceny-specific procedures, you can use the -r7r6 option instead of r7rs:

    % larceny -r7r6
    Larceny v0.98 "General Ripper" (...)

Using the -r7r6 option is equivalent to using the -r7rs option and then importing the (larceny r7r6) library.

Note

One name conflict could not be resolved by adding R7RS extensions to the conflicting R6RS procedure or syntax. When the -r7r6 option is used, the bytevector-copy! procedure is imported with R7RS semantics, and the older R6RS version of that procedure is renamed to r6rs:bytevector-copy!.

The features procedure will return a list of all cond-expand features and libraries available to you. That procedure reads the source code for all library files found in your current Larceny library path, so don't be surprised if it takes a few seconds.

    > (features)
    (r7rs r6rs larceny larceny-0.98
     exact-closed ratios exact-complex complex ieee-float
     full-unicode full-unicode-strings unicode-7
     posix unix gnu-linux i386 ilp32 little-endian
     ...
     (rnrs arithmetic bitwise (6))
     (rnrs arithmetic fixnums (6))
     (rnrs arithmetic flonums (6))
     (rnrs bytevectors (6))
     ...
     (rnrs (6))
     (scheme base)
     (scheme case-lambda)
     (scheme char)
     (scheme complex)
     (scheme cxr)
     (scheme eval)
     (scheme file)
     (scheme inexact)
     (scheme lazy)
     (scheme load)
     (scheme process-context)
     (scheme r5rs)
     (scheme read)
     (scheme repl)
     (scheme time)
     (scheme write)
     (srfi 1)
     (srfi 1 lists)
     ...)

3.3.1. Automatic loading

As an extension to the R7RS and R6RS, Larceny attempts to load libraries automatically when they are first imported. Autoloading makes interactive development and separate compilation much more convenient.

All of Larceny's predefined libraries can be autoloaded.

To enable autoloading of other R7RS/R6RS libraries, including libraries you've written yourself, you can:

3.3.2. Explicit loading

Larceny automatically loads R7RS/R6RS libraries when they are first imported. This is usually the most convenient way to load a library, but autoloading can't be used to load a top-level program. Explicit loading is needed for top-level programs, for libraries that don't reside in Larceny's current-require-path, and for libraries that are defined in files whose names do not follow Larceny's standard naming conventions.

In theory, explicit loading is the only portable way for R7RS programs to load a library. There is no portable way for R6RS programs to load or import libraries, so R6RS programs must rely upon implementation-specific mechanisms such as Larceny's autoloading.

For explicit loading of nonstandard libraries, top-level programs, or unadorned R5RS-style code from a file, you must first import a suitable load procedure:

    > (import (scheme load))

Loading a library does not automatically import it. To use the variables and syntax that are exported by a library, you must import that library explicitly:

    > (load "lib/R6RS/larceny/benchmarking.sls")
    > (import (larceny benchmarking))
    > (time (vector-for-each + (make-vector 1000000 0)))
    Words allocated: 3053286
    Elapsed time...: 25 ms (User: 25 ms; System: 0 ms)
    Elapsed GC time: 3 ms (CPU: 2 in 2 collections (1 minor).)

In Larceny, you may omit the call to load because the (larceny benchmarking) library will be autoloaded when it is imported. In other implementations of the R7RS, you may have to load all of the nonstandard libraries that will be imported by a top-level program or library before you load that top-level program or library.

3.3.3. Predefined libraries

Larceny predefines several nonstandard libraries in addition to the standard R7RS and R6RS libraries, and autoloads them for your convenience. The predefined, autoloadable libraries include:

Composite library:

(larceny r7r6)                         ; all R7RS/R6RS standard libraries

R7RS standard libraries:

(scheme base)
(scheme case-lambda)
(scheme char)
(scheme complex)
(scheme cxr)
(scheme eval)
(scheme file)
(scheme inexact)
(scheme lazy)
(scheme load)
(scheme process-context)
(scheme r5rs)
(scheme read)
(scheme repl)
(scheme time)
(scheme write)

R6RS standard libraries:

(rnrs base (6))                        ; R6RS chapter 9
(rnrs unicode (6))                     ; R6RS library chapter 1
(rnrs bytevectors (6))                 ; R6RS library chapter 2
(rnrs lists (6))                       ; R6RS library chapter 3
(rnrs sorting (6))                     ; R6RS library chapter 4
(rnrs control (6))                     ; R6RS library chapter 5
(rnrs exceptions (6))                  ; R6RS library section 7.1
(rnrs conditions (6))                  ; R6RS library sections 7.2 and 7.3
(rnrs io ports (6))                    ; R6RS library sections 8.1 and 8.2
(rnrs io simple (6))                   ; R6RS library sections 8.1 and 8.3
(rnrs files (6))                       ; R6RS library chapter 9
(rnrs programs (6))                    ; R6RS library chapter 10
(rnrs arithmetic fixnums (6))          ; R6RS library section 11.2
(rnrs arithmetic flonums (6))          ; R6RS library section 11.3
(rnrs arithmetic bitwise (6))          ; R6RS library section 11.4
(rnrs syntax-case (6))                 ; R6RS library chapter 12
(rnrs hashtables (6))                  ; R6RS library chapter 13
(rnrs enums)                           ; R6RS library chapter 14
(rnrs (6))                             ; R6RS library chapter 15
(rnrs eval (6))                        ; R6RS library chapter 16
(rnrs mutable-pairs (6))               ; R6RS library chapter 17
(rnrs mutable-strings (6))             ; R6RS library chapter 18
(rnrs r5rs (6))                        ; R6RS library chapter 19

R6RS standard libraries that are autoloadable but deprecated in Larceny because they have been superseded by the R7RS and SRFI 99 record facilities:

(rnrs records procedural (6))          ; R6RS library section 6.3
(rnrs records inspection (6))          ; R6RS library section 6.4
(rnrs records syntactic (6))           ; R6RS library section 6.2

SRFI libraries:

(srfi 1 lists)                         ; list library
(srfi 2 and-let*)                      ; extended `and` and `let*`
(srfi 5 let)                           ; extended version of `let`
(srfi 6 basic-string-ports)            ; basic string ports
(srfi 8 receive)                       ; binding to multiple values
(srfi 9 records)                       ; defining record types
(srfi 11 let-values)                   ; syntax for multiple values
(srfi 13 strings)                      ; string libraries
(srfi 14 char-sets)                    ; character-set library (default)
(srfi 14 unicode)                      ;   for all Unicode characters
(srfi 14 bmp)                          ;   for the Basic Multilingual Plane
(srfi 14 latin-1)                      ;   for ISO 8859-1 (Latin-1)
(srfi 16 case-lambda)                  ; syntax for variable arity
(srfi 17 generalized-set!)             ; generalized set!
(srfi 19 time)                         ; time data types and procedures
(srfi 23 error)                        ; error reporting mechanism
(srfi 25 multi-dimensional-arrays)     ; multi-dimensional array primitives
(srfi 26 cut)                          ; specializing without currying
(srfi 27 random-bits)                  ; sources of random bits
(srfi 28 basic-format-strings)         ; basic format strings
(srfi 29 localization)                 ; localization
(srfi 38 with-shared-structure)        ; i/o for data with shared structure
(srfi 39 parameters)                   ; parameter objects
(srfi 41 streams)                      ; streams
(srfi 42 eager-comprehensions)         ; eager comprehensions
(srfi 43 vectors)                      ; vector library
(srfi 45 lazy)                         ; iterative lazy algorithms
(srfi 48 intermediate-format-strings)  ; format
(srfi 51 rest-values)                  ; rest values hackery
(srfi 54 cat)                          ; still more formatting
(srfi 59 vicinities)                   ; vicinity
(srfi 61 cond)                         ; a more general cond clause
(srfi 63 arrays)                       ; homogeneous, heterogeneous arrays
(srfi 64 testing)                      ; an API for test suites
(srfi 67 compare-procedures)           ; three-way comparison procedures
(srfi 78 lightweight-testing)          ; lightweight testing
(srfi 87 case)                         ; a more general case clause
(srfi 98 os-environment-variables)     ; environment variables
(srfi 99 records)                      ; (composite library)
(srfi 99 records procedural)           ; (procedural API)
(srfi 99 records inspection)           ; (inspection API)
(srfi 99 records syntactic)            ; (syntactic API)
(srfi 101 random-access-lists)         ; fast and purely functional lists
(srfi 111 boxes)                       ; boxes
(srfi 112)                             ; environment inquiry
(srfi 113 sets)                        ; sets and bags
(srfi 114 comparators)                 ; comparators
(srfi 115 regexp)                      ; regular expressions
(srfi 116 ilists)                      ; immutable lists

Note

For backward compatibility, (srfi 1 lists) through (srfi 101 random-access-lists) are also available with the SRFI 97 naming convention in which the number is preceded by a colon, as in (srfi :1 lists). With the more liberal R7RS syntax, that SRFI 97 naming convention is now unnecessary. Larceny has extended the R6RS library syntax to allow R6RS libraries to import R7RS libraries that follow the R7RS naming convention shown in the list above.

SRFI libraries that are autoloadable but deprecated in Larceny, usually because they have been superseded in whole or in part by R6RS syntax or libraries:

(srfi 60 integer-bits)                 ; integers as bits
(srfi 66 octet-vectors)                ; octet vectors
(srfi 69 basic-hash-tables)            ; basic hash tables
(srfi 71 let)                          ; extensions of let, let*, letrec
(srfi 74 blobs)                        ; octet-addressed binary blocks
(srfi 95 sorting-and-merging)          ; sorting and merging

ERR5RS libraries that are autoloadable but deprecated in Larceny because they have been superseded by the R7RS and SRFI 99 record facilities:

(err5rs records procedural)            ; ERR5RS records (procedural API)
(err5rs records inspection)            ; ERR5RS records (inspection API)
(err5rs records syntactic)             ; ERR5RS records (syntactic API)
(err5rs load)                          ; ERR5RS load procedure

Other autoloadable libraries:

(larceny load)                         ; extension of (err5rs load)
(larceny compiler)                     ; separate compilation (R7RS/R6RS)
(larceny benchmarking)                 ; timing facilities
(larceny profiling)                    ; profiling of Scheme code
(larceny r7r6)                         ; all R7RS/R6RS standard libraries
(larceny records printer)              ; custom printing of records
(larceny shivers-syntax)               ; syntax favored by Olin Shivers
(r5rs)                                 ; approximates the R5RS top level
(explicit-renaming)                    ; macros with explicit renaming

3.3.4. Library path

Larceny's autoload feature locates R7RS/R6RS libraries by performing a depth-first search of the directories that belong to Larceny's current-require-path. Libraries will not be autoloaded unless they are defined in files whose names follow Larceny's standard conventions.

The current-require-path is initialized by the startup.sch file in Larceny's root directory.

Larceny's -path command-line option adds one or more directories to the directories in the current-require-path. On most systems, you can specify multiple directories by separating them with a colon; under Windows, use a semicolon as separator instead. The first directory listed will be searched first.

The LARCENY_LIBPATH environment variable can also be used to add one or more directories to the directories in the current-require-path. Multiple directories should be specified as with the -path option.

Tip

If you have a set of portable libraries that run under more than one implementation of the R7RS, and you want to have a special version of some of those libraries for Larceny, you can put all your portable versions in one directory and the Larceny-specific versions in another. When you run Larceny, use the -path option and specify the Larceny-specific directory first.

Note

The -path option cannot be used by Scheme scripts, because command-line options are passed along to the Scheme script without being interpreted by the scheme-script processor.

Warning

We emphasize that these extensions are non-portable. Other implementations of the R7RS or R6RS may not provide anything comparable to Larceny's -path option or LARCENY_LIBPATH environment variable. Even if they do, their mappings from library names to file names may be incompatible with Larceny's.

3.3.5. Defining libraries

As an extension to the R7RS and R6RS, Larceny allows a top-level program or Scheme script to define R7RS/R6RS libraries within the file that contains the top-level program or Scheme script, before the import form that begins the top-level program. These libraries must be arranged so that no library depends upon libraries that come later in the file.

Warning

We emphasize that this extension is non-portable.

3.3.6. Importing procedures from Larceny's underlying R5RS system

Any of Larceny's R5RS-mode top-level procedures can be imported into an R7RS or R6RS library or program by using an import declaration with a primitives clause that names the R5RS procedures to be imported. For example:

    (import (primitives random current-seconds
                        getenv setenv system
                        current-directory file-modification-time)
            (scheme time))

Warning

This feature is highly non-portable. Other implementations of the R7RS or R6RS may not even have an underlying implementation of the R5RS.

3.4. Scheme scripts

On most Unix systems (including Linux and Apple's OS X), Larceny's scheme-script will execute Scheme scripts as described in R6RS non-normative appendix D, with or without the optional script header. To make Scheme scripts executable in their own right, without executing scheme-script directly, add Larceny's root directory to your path as described in doc/HOWTO-INSTALL, or edit scheme-script to define LARCENY_ROOT and copy that edited scheme-script to a directory in your path.

Suppose, for example, that /home/myself/hello is an R7RS/R6RS Scheme script whose first line is the optional script header shown below:

#!/usr/bin/env scheme-script

If you do not have execute permission for this script, or Larceny's root directory is not in your path, you can still run the script from Larceny's root directory as follows:

    % ./scheme-script /home/myself/hello

If you have execute permission for the script, and Larceny's root directory is in your path, you can also run the script as follows:

    % /home/myself/hello

If, in addition, the directory that contains the script is in your path, you can run the script as follows:

    % hello

You may also pass command-line arguments to a Scheme script.

Warning

We emphasize that Scheme scripts are not portable. Scheme scripts are specified only by a non-binding appendix to the R6RS, not by the R6RS proper. Other implementations of the R7RS or R6RS may not support Scheme scripts at all, or may give them a semantics incompatible with Larceny's.

On Unix systems, standard input and output can be redirected in the usual way. In Larceny, standard input corresponds to the textual port initially returned by current-input-port, and standard output corresponds to the textual port initially returned by current-output-port.

Warning

We emphasize that redirection of standard input and output is non-portable. Other implementations of the R7RS or R6RS may not allow redirection, or may identify the standard input and output with ports other than those initially returned by current-input-port and current-output-port.

3.5. R5RS scripting

Suppose hello.sch contains the following R5RS code:

    (display "Hello world!")
    (newline)
    (exit)

You can run hello.sch as a script by executing Larceny as follows:

    % larceny -nobanner -- hello.sch

You can redirect Larceny's standard input, in which case you may want to eliminate the herald announcement and the read/eval/print loop's prompt:

    % larceny -nobanner -- -e "(begin (herald #f) (repl-prompt values))" \
              < hello.sch

For an explanation of why that works, which may suggest other creative uses of Larceny, ask for help:

    % larceny -help

3.6. Errors

In R6RS mode, which is batch-only, errors should result in an error message followed by a clean exit from the program.

If your program encounters an error in an interactive mode (R5RS or R75RS), it will enter the debugger; this is believed to be a feature.

Despite its crudity, and to some extent because of it, Larceny's debugger works at least as well with optimized compiled code as with interpreted code.

If you type a question mark at the debugger prompt, the debugger will print a help message. That message is more helpful if you understand the Twobit compiler and Larceny's internal representations and invariants, but this manual is not the place to explain those things.

The debugging context is saved so you can exit the debugger and re-enter it from the main read/eval/print loop's prompt:

    > (debug)

The debugger is pretty much a prototype; you don't need to tell us how bad it is.

3.7. Troubleshooting

3.7.1. Errors when starting Larceny

Although Larceny runs on x86-64 machines, it requires 32-bit libraries that are not always installed on Linux and MacOS X machines. If those libraries are absent, the operating system will probably give you a mysterious or misleading error message when you try to run Larceny. For example, the operating system's loader may tell you "larceny.bin not found" even though it's perfectly obvious that larceny.bin is present within Larceny's root directory. To install the necessary 32-bit libraries on Linux machines with x86-compatible processors, someone with superuser privileges must incant

    sudo apt-get install lib32z1
    sudo apt-get install libc6-i386

Warning

The names of those 32-bit packages have changed over time, and may change again.

For Macintosh machines, someone with administrative privileges must install the Apple Developer Command Line Tools.

When attempting to run an R7RS/R6RS program, you may see a warning about "loading source in favor of stale fasl file", following by a long series of error messages about syntactic keywords used as a variable, ending with the kind of error you'd expect to see when a large R7RS/R6RS program is fed to a Scheme compiler that was expecting to see R5RS-compatible code. That means the R7RS/R6RS runtime and standard libraries were not installed correctly, or their source files have been touched or modified since they were last compiled. To fix the problem, recompile the R7RS standard libraries.

The precompiled binary forms of Larceny should run on most machines that use an appropriate processor and operating system, but the executable program "larceny.bin" may be incompatible with very old or with very new versions of the processor or operating system. If that appears to be the case, you should see whether a newer version of Larceny fixes the problem. If not, please report the problem to us at larceny@ccs.neu.edu. Please report success stories as well.

3.7.2. Errors when compiling the R7RS runtime

If something goes wrong while compiling the R7RS runtime, make sure you are running the copy of Larceny you think you are running and have read and write permission for lib/R7RS, lib/R6RS, lib/SRFI, and all their subdirectories and files. If you get an error message about something being "expanded against a different build of this library", then one or more of the compiled files in lib/R7RS or lib/R6RS or lib/SRFI or its subdirectories has gone stale. Removing all .slfasl files from lib/R6RS and lib/SRFI and their subdirectories will eliminate the stale file(s).

Warning

Don't remove the .sch, .scm, .sls, or .sld files.

3.7.3. Autoloading errors

If Larceny attempts to autoload an imported R7RS/R6RS library but cannot find the library, then the library may be defined in a file that doesn't follow Larceny's standard naming conventions. Another possibility is that the -path option was omitted or incorrect.

If an R7RS/R6RS library is recompiled, then all compiled libraries and top-level programs that depend upon it must also be recompiled. In particular, recompiling the standard R7RS runtime will invalidate all compiled libraries and top-level programs. Larceny's compile-stale script and the compile-stale-libraries procedure of (larceny compiler) make it convenient to recompile all of the libraries and top-level programs within any given directory in an order consistent with their dependencies.

3.7.4. Crashes

Please report all crashes with as much information is possible; a backtrace from a debugger or a core dump is ideal (but please do not mail the core dump without contacting us first). Larceny's run-time system is compiled with full debugging information by default and a debugger like GDB should be able to provide at least some clues.

3.8. Performance

By default, Larceny's Twobit compiler performs several optimizations that are fully compatible with the R7RS but may not be fully compatible with the older R6RS, R5RS, and IEEE-1178 standards.

When compiling R5RS code, Larceny's Twobit compiler normally makes several assumptions that allow it to generate faster code; for example, the compiler assumes Scheme's standard procedures will not be redefined.

To obtain strict conformance to R5RS semantics at the expense of slower code, use R5RS mode and evaluate the expression

    (compiler-switches 'standard)

To make the compiler generate faster code, you can promise not to redefine standard procedures and not to redefine any top-level procedure while it is running. To make this promise, evaluate

        (compiler-switches 'fast-safe)

To view the current settings of Twobit's numerous compiler switches, evaluate

        (compiler-switches)

All of Twobit's compiler switches are procedures whose setting can be changed by passing the new value of the switch as an argument.

For more information, evaluate

        (help)

Note

That help procedure is predefined only in R5RS mode, and some of the help information that will be printed may be irrelevant to the heap image you are using.

To alter the compiler switches from R7RS mode, or to disable certain compiler optimizations that are incompatible with the R6RS, see the section that describes the (larceny compiler) library.