9. Larceny's R7RS/R6RS libraries

Larceny provides libraries for compiling R7RS/R6RS libraries and for timing benchmarks.

9.1. Load

The (larceny load) library exports both the load procedure of (scheme load) and Larceny's r5rs:require procedure, which is a renaming of the require procedure used by Larceny's R5RS mode.

In Larceny's R7RS mode, the load procedure can load R5RS libraries and programs as well as R7RS/R6RS libraries.

The r5rs:require procedure should be used only for dynamic loading of R5RS libraries into Larceny's underlying R5RS system. The variables defined by that library can be imported into an R7RS session or R7RS/R6RS library or program using a primitives clause in an import form.

Warning

These procedures should be used only at an interactive top level and in files that will be loaded into an interactive top level. Calls to these procedures have no effect at compile time, and should not appear in files that will be compiled separately; use the define-library and import syntaxes instead.

9.2. Compiler

The (larceny compiler) library exports the load and r5rs:require procedures of (larceny load), the current-require-path procedure, the compile-file, compile-library, and compile-stale-libraries procedures described below, and the compiler-switches procedure.

These procedures can be used to compile R7RS/R6RS libraries and top-level programs before they are imported or executed. This is especially important for Petit Larceny, which would otherwise use an interpreter. For native Larceny, whose just-in-time compiler generates native machine code as source libraries and programs are loaded, imported, or executed, the main advantage of separate compilation is that compiled libraries and programs will load much faster than source libraries and programs.

The main disadvantage of separate compilation is that compiled libraries and programs go stale when their source code is changed or when a library on which they depend is changed or recompiled. Stale libraries and programs can be dangerously inconsistent with libraries on which they depend, so Larceny checks for staleness and refuses to execute a stale library or program. The compile-stale-libraries procedure provides a convenient way to recompile stale libraries and programs.

(compile-file sourcefile [slfaslfile])

Compiles sourcefile, which must be a string naming a file that contains source code for one or more R7RS/R6RS libraries or a top-level program. If slfaslfile is supplied as a second argument, then it must be a string naming the file that will contain the compiled code; otherwise the name of the compiled file is obtained from sourcefile by replacing the ".sld" or ".sls" suffix with ".slfasl".

Procedure compile-library

(compile-library sourcefile [slfaslfile])

Compiles sourcefile, which must be a string naming a file that contains source code for one or more R7RS/R6RS libraries. Apart from its unwillingness to compile top-level programs, compile-library behaves the same as compile-file above.

Procedure compile-stale-libraries

(compile-stale-libraries )

(compile-stale-libraries changedfile)

If no argument is supplied, then all ".sld" and ".sls" files that lie within the current directory or a subdirectory are recompiled.

If changedfile is supplied, then it must be a string giving the absolute pathname of a file. (In typical usage, changedfile is a source file that has been modified, making it necessary to recompile all files that depend upon it.) Compiles all R7RS/R6RS library files that lie within the same directory as changedfile or a subdirectory, and have not yet been compiled or whose compiled files are older than changedfile.

Note

In future versions of Larceny, compile-stale-libraries might compile only the source files that depend upon changedfile.

Procedure compiler-switches

(compiler-switches )

(compiler-switches mode)

If no argument is supplied, then the current settings of all compiler switches are displayed. Each of those switches is itself a parameter that is exported by the (larceny compiler) library. Calling any individual compiler switch with no arguments will return its current setting. Calling any individual compiler switch with an argument (usually a boolean) will change its setting to that argument.

The compiler-switches procedure may also be called with one of the following symbols as its argument:

default sets most compiler switches to their default settings.

fast-safe enables all optimizations but continues to generate code to perform all run-time type and range checks that are needed for safety (in the traditional sense, not the R6RS sense).

fast-unsafe enables all optimizations and also disables type and range checking. This setting is deprecated because it compromises safety (in the traditional sense).

slow turns off all optimizations.

standard sets compiler switches for maximal conformance to the R5RS and R6RS standards.

Warning

The standard setting is deprecated because it generates very slow code (because the R5RS makes it difficult to inline standard procedures), disables most compile-time checking (because the R6RS forbids rejection of programs with obvious errors unless the R6RS classifies the errors as syntactic), and may also compromise the portability or interoperability of R7RS/R6RS libraries and programs (because the R6RS outlaws several extensions that Larceny uses to improve its compatibility with other implementations of the R5RS, R6RS, and R7RS as well as interoperability between Larceny's own R5RS and R7RS/R6RS modes).

Tip

Selective toggling of compiler switches is almost always better than using the standard setting. To improve R5RS conformance without sacrificing too much performance, set the benchmark-mode switch to false and set the integrate-procedures switch to false only when compiling files that need to be sensitive to redefinitions of standard procedures. For R6RS libraries and programs, setting the benchmark-mode and global-optimization switches to false will eliminate a couple of minor conformance issues with only a small loss of performance and without sacrificing compile-time checking or portability. For R7RS libraries and programs, the compiler's default settings already conform to the R7RS.

9.3. Benchmarking

The (larceny benchmarking) library exports the time syntax and run-benchmark procedure described below.

Syntax time

(time expression)

Evaluates expression and returns its result after printing approximations to the storage allocated and time taken during evaluation of expression.

    > (time (fib 30))
    Words allocated: 0
    Words reclaimed: 0
    Elapsed time...: 49 ms (User: 48 ms; System: 0 ms)
    Elapsed GC time: 0 ms (CPU: 0 in 0 collections.)
    832040

(run-benchmark name iterations thunk predicate)

Given the name of a benchmark, the number of iterations to be performed, a zero-argument procedure thunk that runs the benchmark, and a unary predicate that checks the result of thunk, prints approximations to the storage allocated and time taken by iterations calls to thunk.

    > (run-benchmark "fib30"
                     100
                     (lambda () (fib 30))
                     (lambda (x) (= x 832040)))

    --------------------------------------------------------
    fib30
    Words allocated: 0
    Words reclaimed: 0
    Elapsed time...: 4828 ms (User: 4824 ms; System: 4 ms)
    Elapsed GC time: 0 ms (CPU: 0 in 0 collections.)

9.4. Records printer

The (larceny records printer) library exports the two procedures described below. These procedures can be used to override Larceny's usual printing of records and opaque types that were defined using the records libraries.

Procedure rtd-printer

(rtd-printer rtd) => maybe-procedure

Given a record type descriptor, returns its custom print procedure, or returns false if the rtd has no custom print procedure.

Procedure rtd-printer-set!

(rtd-printer-set! rtd printer)

Given a record type descriptor rtd and a printer for instances of that rtd, installs printer as a custom print procedure for rtd. The printer should be a procedure that, given an instance of the rtd and a textual output port, writes a representation of the instance to the port.