Is it possible to change the search / reference order for DrRacket / Scheme in the library?

I am following the instructions in 3.3.3 SICP to create the table.

Here is code_0.scm

:

;code_0.scm
#lang scheme
(require rnrs/base-6)
(require rnrs/mutable-pairs-6)

(define nil '())

(define (make-table)
  (list '*table*))

(define (assoc key records)
  (cond ((null? records)
         false)
        ((equal? key (caar records))
         (car records))
        (else
         (assoc key (cdr records)))))

(define (insert! key value table)
  (let ((record (assoc key (cdr table))))
    (if record
        (set-cdr! record value)
        (set-cdr! table
                  (cons (cons key value)
                        (cdr table)))))
  'OK)

(define (lookup key table)
  (let ((record (assoc key (cdr table))))
    (if record
        (cdr record)
        false)))


(define table (make-table))

(insert! 0 0 table)
(insert! 1 1 table)
(insert! 2 2 table)

      

code_0.scm

works well, but not after becoming an external referenced file code_1.scm

:

; I remove #lang scheme

in code_0.scm

at the moment

;code_1.scm
#lang scheme/load
(load "code_0.scm")

(define table-0 (make-table))
(insert! 0 0 table-0)
(insert! 1 1 table-0)
(insert! 2 2 table-0)

      

The error is displayed in DrRacket:

assoc: invalid list: {{0. 0}}

As per the previous question, I stopped, it was because the "assoc" function was already defined in the Scheme library (or in the DrRacket library?) That the compiler would decide to link the standard / system that came before mine.

So, is it possible to change the search / link order on DrRacket / Scheme?

If so, how?

If not, is it a compiler or language defect?

Is there any other way to avoid this other than implementing it directly in the main file if I need to create a duplicate name function?

+3


source to share


3 answers


This is not a direct answer to your problem, but a description of the mess you got into, that this problem ended up in, and will lead to other problems too.

I'll first try to explain how Racket evaluates a module very quickly, as it will have to do with understanding the clutter. It sounds like you're trying to use "just a diagram", 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 decide this particular one.)

In the usual case of files, .rkt

each file is evaluated in its own namespace, which is filled with bindings from (1) #lang

which you specify and (2) various libraries (= other modules) which you require

. So when you have

#lang foo
(require bar)

      

you start with a new namespace, grab all the bindings from foo

into that namespace, and then add the bindings from bar

. In case of collisions, the bindings require

will be shadow from the language, so if both provided some function f

, the name your code will use is one of bar

. If you need more than one library:

#lang foo
(require bar baz)

      

and both bar

and baz

provide f

, then you will get an error if they differ from f

s. This can happen if, for example, bar

provides inline cons

and baz

provides cons

that creates mutable pairs (i.e. provides inline mcons

as cons

). You won't get an error if both of them provide the same ones f

, though.

Again, note that this is different from the "initial bindings" which is what you get from #lang

- the latter require

will just be shadowed if the same name is used. The reason for the bindings in #lang

other words, they provide some basic bindings that the code uses at a fundamental level. For example, the language bindings you get require

, which you use later. Another example is a #%module-begin

macro that wraps the entire body of a module - a tool that can be used to convert all expressions to something else, for example, this is how expressions are expressed in a language racket

their meaning is printed.

Roughly speaking, libraries (= modules) in the racket are broken down into language modules and library modules. It's not that formal, since both are implemented in the same way: modules that provide things. The difference is that they provide, where language modules typically provide a variety of bindings, including base such as require

and #%module-begin

, and what you expect from lispish language, such as define

, if

, cond

, +

, cons

, etc.

In the normal case, therefore, you don't run into too many collision problems as the libraries try to avoid common names. But if you try a require

language module as if it were a library, you run into problems like this very quickly, since language modules tend to provide many names, including the very common names I listed above.

Now you can see how this is the problem in your code0.scm

:



#lang scheme
(require rnrs/base-6)
(require rnrs/mutable-pairs-6)

      

what it means, use bindings first scheme

. This scheme

language is not a standard schema - it is a precursor to a racket

language dating from before the name change, when Racket was known as PLT Scheme, and therefore scheme

had to be a "dialect of the scheme" that PLT Scheme uses by default. "Among other things, it is unchanged pairs such the same as the ones you get in the files #lang racket

.

But later, you will copy most of the bindings rnrs

, and the ones that use mutable pairs that you found are different. You need a module that is usually used as a language, so most of the bindings you use will work fine, but sooner or later you will run in a binding from scheme

that is not shaded by one rnrs

, and if it is something to do with pairs , you will have problems.

So the takeaway here is to avoid mixing up two such languages: either stick #lang scheme

or #lang r6rs

. In the former case, you can also switch to #lang racket

and use the regular library racket, 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, use the SICP language that Neil Van Dyck wrote.

But you have even more problems. In yours code_1.scm

you are using it scheme/load

as a language, and something that can do it is possible to do what you are trying to do - but it brings with it a whole bunch of other problems. I'm looking for documentation for scheme/load

(which will send you to the docs for a racket/load

more modern title) you'll see some things about eval

and load

. This is because at some point people wanted to write one file that has several modules, but that was impossible. (Now this, and you get submodules, but racket/load

still supported.) scheme/load

was implemented to solve this problem: using it as if you were entering expressions into one REPL, so you can define a bunch of modules and use them. But because of this, it is a strange language, and if you do not need this feature, you should avoid it.

load

the name is what it should have been, what prevents people from using it ... The thing is, it load

is an old and primitive tool for structuring code, which was the only thing available in the standard language before R5RS. The thing is that it is (again, this is a rough description) of the read

expressions from the file and eval

uate them. The problem is that you end up with one namespace for everything, and worse, each definition could actually be a mutation of the previous definition, if one existed. This means that even simple type definitions

(define (add1 x) (+ 1 x))

      

are unsafe because a later load

file may override +

this definition in a way that violates this definition. In short, it's a very messy world where many libraries provide you with the same names, but with different semantics. IOW, this is usually a mess in Racket. Racket (and later R6RS) uses modules in such a way as to sort it all out in a much better way - there is no single namespace and mutations, just names that are provided from private modules. In fact, mutation is still there, but it is more limited in the damage you can get (this is only used in the REPL); and are load

also, along with eval

, and are usually avoided as tools for organizing source files.

The usage load

also explains why you had to remove the line #lang

when you used it - when you load

file with a module definition, you get exactly that definition - a module. To actually use the things that the module provides, you also need to add (require 'code_0)

. Another thing is that deleting a line is #lang

usually as long as you are left without the necessary bindings for any sane piece of code - but in your case, you require

d the whole language later, which continued to work, only with subtle differences.

So the second high-level takeaway is to avoid load

- it's a bad tool. Also, avoid languages scheme/load

or languages racket/load

if you really know what they do and need this feature.

+10


source


The error you are seeing assoc: not a proper list: {{0 . 0}}

needs an explanation.

In Racket, you can create immutable pairs with cons

and mutable pairs with mcons

. Usually cons

immutable pairs are also created in Scheme , but since you have strings

(require rnrs/base-6)
(require rnrs/mutable-pairs-6)

      

all standard list functions are replaced with those that create mutable ones.

Note that mutable and immutable pairs are two completely separate data types, although they are both called pairs.

Somewhere in the system, there are certain primitives, say, prim-mcons

and prim-icons

that create mutable and immutable pairs. #lang scheme

binds cons

to prim-mcons

and #lang racket

binds cons

to prim-icons

.

This affects all standard list functions. assoc

from rnrs/mutable-pairs-6

expects a list of changed pairs, and Racket assoc

expects a list of unchangeable pairs. Hence the error.

How can you notice this? In Racket, where you can use both mcons

, and cons

standard list operations create lists with immutable pairs, and the printer prints them with (...)

. Mutable pairs are printed with curly braces {...}

.



Mistake

assoc: not a proper list: {{0 . 0}}

      

shows lists of curly brace associations. This means that the association list has been created on the diagram using changeable pairs.

To fix the problem, you need to use the correct one assoc

. You can do this by adding the lines

(require rnrs/base-6)
(require rnrs/mutable-pairs-6)

      

to the second file.

Note. The language is #lang scheme

not one of the RnRS schemas, but the dialect that Racket used before the project name changed.

Note 2: Why did Racket remove volatility with pairs in the first place? Well, in a well-written Scheme code, you rarely see set-car!

and set-cdr!

. Having a guarantee that the pair never mutates allows for various optimizations that allow most programs to run faster (one length

can use a constant time). So the choice was to make immutable pairs standard and contain modified pairs for whatever programs they absolutely need.

+2


source


I get no errors with your file in DrRacket. The file you load

are probably the old file from the last question. This is the only logical conclusion, since none of the files given here use assoc

, but the old ones.

It is not recommended to mix Schemes and Rocket. #lang scheme

(or #!scheme

) is the old name for #!racket

today, and it will import all the symbols currently in #!racket

, and your instructions require

in addition to that.

The pod libraries rnrs

are intended to be used by the R6RS language, so the first line should be #!r6rs

and should be used instead (import (rnrs base) (rnrs mutable-pairs))

. In R6RS you can import except some symbols. For example. (import (except (rnrs base) cons))

does not import cons

, but everything else. I didn't use assoc

since there isn't assoc

in (rnrs base)

and (rnrs mutable-pairs)

, so it probably was from #!scheme

( #!racket

)

If you plan on using your dictionary as a library, you can make it an R6RS library and import it instead of using it load

.

Also note that Racket also includes the SICP compatibility language . It is based on #!r5rs

, and most of the examples in the book work as well!

+1


source







All Articles