• Traveling between two worlds back and forth: | ||
• Three forms of import: |
When you start Gauche, either in REPL or as a script, you’re in
user
module, which inherits gauche
module.
Likewise, when you read a library, the initial module inherits
gauche
module (until you call select-module
).
That’s why you can access all the built-in procedures of Gauche
without saying (use something)
. (See Module inheritance, for
the details about inheriting modules).
On the other hand, R7RS requires to be explicit about which namespaces
you’ll be using, by import
form, e.g. (import (scheme base))
.
Besides, R7RS library must be explicitly enclosed by define-library
form.
Before the first import
form of a program, or outside of
define-library
, is beyond R7RS world—the standard defines
nothings about it.
These facts let Gauche to set up appropriate “world”, and you can use R7RS code and traditional Gauche code transparently.
NB: As explained in Three import forms,
R7RS import
is rather different from Gauche
import
, so we note the former r7rs#import
and the latter
gauche#import
in this section for clarity. When you write code
don’t use prefixes r7rs#
and gauche#
; just write import
.
The define-library
form is defined as a macro in gauche
module;
it sets up R7RS environment before evaluating its contents.
So, when you load an R7RS library (either from Gauche code via use
form, or from R7RS code via r7rs#import
form),
Gauche starts loading the file in gauche
module, but immediately
see define-library
form, and the rest is handled in R7RS
environment.
Suppose you have an R7RS library (mylib foo)
with the following code:
(define-library (mylib foo) (import (scheme base)) (export snoc) (begin (define (snoc x y) (cons y x))))
It should be saved as mylib/foo.scm in one of the directories in
*load-path*
.
From R7RS code, this library can be loaded by r7rs#import
:
(import (mylib foo)) (snoc 1 2) ⇒ (2 . 1)
To use this library from Gauche code, concatenate elements of library
names by .
to get a module name, and use
it:
(use mylib.foo) (snoc 1 2) ⇒ (2 . 1)
To use Gauche library foo.bar
from R7RS code,
split the module name by .
to make a list for the name
of the library. For example, gauche.lazy
module can be
used from R7RS as follows:
(import (gauche lazy))
For SRFI modules, R7RS implementations have a convention to
name it as (srfi n)
, and Gauche follows it.
The following code loads SRFI-1 and SRFI-13 from R7RS code:
(import (srfi 1) (srfi 13))
(It’s not that Gauche treat srfi
name specially; installation
of Gauche includes adapter libraries such as srfi/1.scm.)
A tip: To use Gauche’s built-in features (the bindings that are
available by default in Gauche code) from R7RS code, import
(gauche base)
library (see gauche.base
- Importing gauche built-ins):
(import (gauche base)) filter ⇒ #<closure filter>
R7RS scripts always begin with import
form. However, r7rs#import
has a different syntax and semantics
from gauche#import
—so we employ a trick.
When gosh
is started, it loads the given script file
in user
module. We have a separate user#import
macro, which
examines its arguments and if it is R7RS import syntax, switch to the
r7rs.user
module and run the r7rs#import
. Otherwise, it
runs gauche#import
. See Three import forms, for the details.
An example of R7RS script:
(import (scheme base) (scheme write)) (display "Hello, world!\n")
If you’re already familiar with Gauche scripts, keep in mind that
R7RS program doesn’t treat main
procedure specially; it
just evaluates toplevel forms from top to bottom. So the following
script doesn’t output anything:
(import (scheme base) (scheme write)) (define (main args) (display "Hello, world!\n") 0)
To access the command-line arguments in R7RS scripts, use
command-line
in (scheme process-context)
library
(see scheme.process-context
- R7RS process context, also see Command-line arguments).
When gosh
is invoked with -r7
option and no script file is
given, it enters an R7RS REPL mode. For the convenience, the following
modules (“libraries”, in R7RS term) are pre-loaded.
(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 read) (scheme repl) (scheme time) (scheme write)
Besides, the history variables *1
, *2
, *3
,
*1+
, *2+
, *3+
, *e
and *history
are available (See Working in REPL, for the details of history variables).
You can know you’re in R7RS REPL by looking at the prompt, where
gosh
shows the current module (r7rs.user
):
gosh[r7rs.user]>
To switch Gauche REPL from R7RS REPL, import (gauche base)
and
select user
module using select-module
:
gosh[r7rs.user]> (import (gauche base)) #<undef> gosh[r7rs.user]> (select-module user) #<undef> gosh>
(You can (select-module gauche)
but that’s usually not what you
want to do—changing gauche
module can have unwanted side effects.)
When you’re working on R7RS code in file and load it into R7RS REPL
(for example, if you’re using Emacs Scheme mode, C-c C-l does the job),
make sure the file is in proper shape as R7RS; that is, the file
must start with appropriate import
declarations, or
the file contains define-library
form(s). If you load
file without those forms, it is loaded into Gauche’s user
module
no matter what your REPL’s current module is,
and the definitions won’t be visible from r7rs.user
module
by default.
By default, gosh
enters Gauche REPL when no script file is given.
See Working in REPL, for detailed explanation of using REPL.
To switch Gauche REPL to R7RS REPL, simply use r7rs-style import;
user#import
knows you want R7RS and make a switch.
gosh> (import (scheme base)) #<undef> gosh[r7rs.user]>
If you don’t start gosh
with -r7
option, however,
only the libraries you given to user#import
are loaded at
this moment.
If you want to switch the “vanilla” r7rs environment, that is, even
not loading (scheme base)
, then you can use r7rs
module and directly select r7rs.user
:
gosh> (use r7rs) gosh> (select-module r7rs.user) gosh[r7rs.user]>
If you do this, the only
bindings visible initially are import
and define-library
;
even define
is undefined!
You have to manually do (import (scheme base))
etc. to start
writing Scheme in this environment.
For historical reasons, Gauche has three import
forms; the original
Gauche’s import
, R7RS import
, and the hybrid import
.
Usually it is clear that the code is written in traditional Gauche
or in R7RS, and usage of import
is typically idiomatic, so there’s
not much confusion in practice. Only when you talk about import
outside of code, you might need to specify which one you’re talking.
The hybrid import
is what we described user#import
in
the previous section (see Traveling between two worlds back and forth).
It understands both of Gauche’s import
and
R7RS import
.
So what you really need to know is the first two.
Gauche’s module system design is inherited from STk, and we’ve been
used import
for purely name-space level operation; that is,
it assumes the module you import from already exists in memory.
Loading a file that defines the module (if necessary) is
done by separate primitives, require
. In most cases one file
defines one module, and using that module means require
it then
import
it (it’s so common that Gauche has a macro for it—use
).
However, separating those two sometimes comes handy when you need
some nontrivial hacks. See Using modules, for the details of
Gauche’s import
.
R7RS leaves out the relation between modules (libraries) and files
in order to give implementation freedom. If necessary, its import
must load a file implicitly and transparently. So R7RS’s import
is semantically Gauche’s use
.
The hybrid import
only appears at the beginning of the Scheme
scripts. It finds out whether the script is in the traditional Gauche
code or in the R7RS code. See Traveling between two worlds back and forth, for the details.
Now we’ll explain R7RS import
:
[R7RS] Imports libraries specified by import-specs. What R7RS calls libraries are what Gauche calls modules; they’re the same thing.
R7RS libraries are named by a list of symbols or integers,
e.g. (scheme base)
or (srfi 1)
.
It is translated to Gauche’s module name by joining the symbols
by periods; so, R7RS (scheme base)
is Gauche’s scheme.base
.
Conversely, Gauche’s data.queue
is available as
(data queue)
in R7RS. To use those two libraries,
R7RS program needs this form at the beginning.
(import (scheme base) (data queue))
It works just like Gauche’s use
forms; that is, if the named
module doesn’t exist in the current process, it loads the file; then
the module’s exported bindings become visible from the current module.
(use scheme.base) (use data.queue)
(You may wonder what if R7RS library uses symbols with periods in them. Frankly, we haven’t decided yet. It’ll likely be that we use some escaping mechanism; for the time being you’d want to stick with alphanumeric characters and hyphens as possible.)
Just like Gauche’s use
, you can select which symbols to be
imported (or not imported), rename specific symbols, or add
prefix to all imported symbols. The formal syntax
of R7RS import syntax is as follows:
<import declaration> : (import <import-set> <import-set> ...) <import-set> : <library-name> | (only <import-set> <identifier> <identifier> ...) | (except <import-set> <identifier> <identifier> ...) | (prefix <import-set> <identifier>) | (rename <import-set> (<identifier> <identifier>) (<identifier> <identifier>) ...) <library-name> : (<identifier-or-base-10-integer> <identifier-or-base-10-integer> ...)