This is not a direct answer for your problem, but a description of the
mess you've gotten yourself into which eventually got to that problem,
and will lead to other problems too.
I'll try to first explain how Racket evaluates a module very briefly,
since it'll be relevant to understanding the mess. It looks like you're
trying to use "just scheme" so you're probably not too interested in
this, but you should still read it to understand the problems you're in.
(Even if you solved that particular one.)
In the usual case of .rkt
files each file is evaluated in its own
namespace, which is populated by bindings from (1) the #lang
that you
specify, and (2) various libraries (= other modules) that you require
.
So when you have
#lang foo
(require bar)
you start from a fresh namespace, grab all of the bindings from foo
into this namespace, and then you add the bindings from bar
. In case
of clashes, the require
bindings will shadow ones from the language,
so if both of them provided some function f
, the name that your code
will use will be the one from bar
. If you require more than one
library:
#lang foo
(require bar baz)
and both bar
and baz
provide f
, then you'll get an error if
these are different f
s. This can happen if, for example, bar
provides the builtin cons
and baz
provides a cons
that creates
mutable pairs (ie, provides the builtin mcons
as cons
). You will
not get an error if both of them provide the same f
though.
Again, note that this is different from the "initial bindings" which is
what you get from the #lang
-- a latter require
will just shadow
them if the same name is used. The reason for the #lang
bindings
treated differently is that they provide some basic bindings that the
code uses at a fundamental level. For example, the language bindings
will get you the require
that you use later on. Another example is a
#%module-begin
macro that wraps the whole module body -- a tool that
can be used to transform all expressions into something else, for
example, this is how toplevel expressions in the racket
language get
their value printed.
Roughly speaking, libraries (= modules) in racket are split into
language modules and library modules. This is not something that is
formal since both are implemented in the same way: modules that provide
stuff. The difference is in the kind of stuff that they provide, where
language modules will usually provide lots of bindings, include basic
ones like require
and #%module-begin
, and things that you expect
from a lispish language like define
, if
, cond
, +
, cons
, etc.
In the usual case, therefore, you don't run into problems of name
clashes too much since libraries try to avoid common names. But if you
try to require
a language module as if its a library, you very quickly
run into such problems since language modules tend to provide lots of
names, including those very common names like the ones I listed above.
Now you can see how this is a problem in your code0.scm
:
#lang scheme
(require rnrs/base-6)
(require rnrs/mutable-pairs-6)
what this does is use the scheme
bindings first. This scheme
language is not standard scheme -- it's the precursor to the racket
language, dating to before the name change when Racket was known as PLT
Scheme, and therefore scheme
was intended to be "the scheme dialect
that PLT Scheme uses by default". Among other things, it has immutable
pairs, same as the ones you get in #lang racket
files.
But later on you pile up most of the rnrs
bindings -- and those use
mutable pairs, which are, as you've discovered, a different type.
You're requiring a module that is usually used as a language, so most
of the bindings you use will work fine, but sooner or later you'll run
into a binding from scheme
that is not shadowed by one from rnrs
,
and if it's something that has to do with pairs, you'll get problems.
So the conclusion here is to avoid mixing up two languages like this:
either stick to #lang scheme
or to #lang r6rs
. In the former case,
you can just as well switch to #lang racket
, and use the usual racket
libraries, and in the latter case you should be careful and try to avoid
importing racket libraries that expect immutable pairs (and more).
Alternatively, if your goal is to do some SICP, then use the SICP
language that Neil Van Dyke
wrote.
But you have more problems, still. In your code_1.scm
you're using
scheme/load
as the language, and that's something that might make it
possible to do what you're trying to do -- but it brings with it a whole
pile of other problems. I you look up the documentation for
scheme/load
(which will send you to the docs for racket/load
, the
more modern name), you'll see some stuff about eval
and load
. This
is because at some point people wanted to be able to write a single file
that has several modules in it, but that was not possible. (Now it is,
and you get submodules -- but racket/load
is still kept around.)
scheme/load
was implemented to address this: using it is as if you're
entering expressions in a single REPL, so you can define a bunch of
modules and use them. But it's an odd language because of this, and if
you don't want that particular feature, you should avoid it.
The load
in the name is something that should have actually been
something that discourages people from using it... The thing is that
load
is an old and primitive tool for structuring code, which was the
only available thing in the standard language up to R5RS. The thing
that it does is (again, this is a rough description) read
expressions
from a file and eval
uate them. The problem is that you get a single
namespace for everything, and worse, each definition can actually be a
mutation of a previous definition if one existed. This means that even
simple definitions like
(define (add1 x) (+ 1 x))
are not safe, since a later load
of a file can redefine +
in a way
that breaks this definition. In short, this is very much a mess in a
world where many libraries provide you with the same names but with
different semantics. IOW, it's usually a mess in Racket. Racket (and
later, R6RS) uses modules in a way that sorts the whole thing out in a
much better way -- there's no single namespace and mutation, just names
that are provided from closed modules. Actualy, the mutation thing is
still there, but it is more restricted in the damage you can get (it's
used only in the REPL); and load
is there too, together with eval
,
and they are generally avoided as tools to organize source files.
Using load
also explains why you had to remove the #lang
line when
you've used it -- when you load
a file with a module definition, you
get just that definition -- the module's. To actually use the things
that the module provides, you'd also need to add a (require 'code_0)
.
Yet another thing is that dropping the #lang
line is usually a
disaster since you're left without the necessary bindings for any
reasonable piece of code -- but in your case, you require
d a whole
language later on, which is how things continued to work, only with
subtle differences.
So the second highlevel conclusion is to avoid load
-- it's a bad
tool. Also, avoid the scheme/load
or racket/load
languages unless
you really know what they're doing and need that functionality.