@theau.poulat has joined the channel
@wmblackerby has joined the channel
@kian.melhus has joined the channel
I have a question about Racket’s <https://docs.racket-lang.org/reference/load-lang.html|load language>. Is this a bug for require
in load language?
For example, I have the following directory structure and files: .
├─load-dir
│ │ main.rkt
│ │
│ └─a-lib
│ a-lib.rkt
│ util.rkt
│
main.rkt
#lang racket/load
(require r5rs)
(require "./a-lib/a-lib.rkt")
a-lib.rkt
#lang racket/load
(require r5rs)
(display "a-lib enter\n")
(require "util.rkt")
util.rkt
#lang racket/load
(require r5rs)
(display "util enter\n")
Then I run the main.rkt
in DrRacket, but the following error occurred: a-lib enter
. a-lib\a-lib.rkt:5:9: a-lib\a-lib.rkt:5:9: cannot open module file
module path: #<path:E:\work-pl\racket\code\module\load-language\load-dir\util.rkt>
path: E:\work-pl\racket\code\module\load-language\load-dir\util.rkt
system error: The system cannot find the file specified.; errid=2 in: #<path:E:\work-pl\racket\code\module\load-language\load-dir\util.rkt>
To my knowledge, the require
should be based on the relative path of the current file which being loaded rather than the working directory of the initial file.
Is that right?
Thanks.
Well, racket/load
is pretty much the REPL. The concept of “file” is weird there, so I wouldn’t be surprised if it doesn’t work as you expect. The real question is why are you using it? It’s warned pretty clearly in the doc that:
> For these reasons, use racket/load for interactive exploration of top-level forms only, and not for constructing larger programs.
Though I guess no one cares about asking in the right channel anyway, so perhaps it’s fine.
require
through multiple levels of #lang racket/load
is not a good idea and is unlikely to work reliably
I use racket/load
because racket/load
seems to be able to simulate a poor man module system. Scheme’s R5RS specification has no module system, all the programs run at the top level.
If you want to use load, then just use load for everyting.
For example, I have some pure R5RS Scheme code and I want to play with them in Racket. Or I’d like to write some large portable programs in pure R5RS (splitting a large program into different files).
My current workaround is to create a manifest file for each poor-man module.
Something like: .
├─my-scheme-workspace
│ │ poor-man-module.scm
│ │
│ └─a-lib
│ a-lib.manifest
│ a-lib.scm
│ util.scm
\|
│ └─b-lib
│ b-lib.manifest
│ b-lib.scm
│ util.scm
│
│ └─my-project
│ main.scm
│
a-lib.manifest
("a-lib.scm" "util.scm")
b-lib.manifest
("b-lib.scm" "util.scm")
main.scm
(load "../poor-man-module.scm")
(load-module "../a-lib")
(load-module "../b-lib")
;; ... code here
poor-man-module.scm
;; Poor man module system
;; R5RS has no module system, so make a poor man module system.
(define (load-module mod)
(define (mod->name mod)
(letrec ((mod->name-iter (lambda (i)
(if (char=? (string-ref mod i) #/)
(substring mod (+ i 1) (string-length mod))
(mod->name-iter (- i 1))))))
(mod->name-iter (- (string-length mod) 2))))
(for-each load (with-input-from-file (string-append mod "/" (mod->name mod) ".manifest")
(lambda ()
(map (lambda (x)
(string-append mod "/" x))
(read)))))
)
The code above works fine in plt-r5rs
, no Racket features involved.
The advantage of this approach is that the poor man module (yes, they are all top level programs) supports redefinition, as opposed to Racket’s module system.
But #lang racket/load
seems more flexible. To be honest, I accidentally found this feature in Racket :joy:.
In fact, I have given up the racket/load
approach because it is not portable.
I’m just curious about whether <https://racket.slack.com/archives/C09L257PY/p1600806079027600|the require problem> above is a bug, since load-relative
works fine in racket/load
.
Why have manifests and not just a call to load?
@samth There are three main reasons:
A module may involve many sub-files. It is convenient to use the list in the manifest to record these sub-files.
Because of redefinition, the order of sub-files loading is sensitive, so must use a list to record.
The list in the manifest may be reused in multiple places. for example:
Assuming b-lib
depends on a-lib
, in order to test b-lib
, we just create a test.scm
in b-lib
and (load-module "../a-lib")
:
b-lib/test.scm
(load "../poor-man-module.scm")
(load-module "../a-lib")
(load-module "../b-lib")
;; ... code here
Otherwise we must: b-lib/test.scm
(load "../a-lib/a-lib.scm")
(load "../a-lib/util.scm")
;; ... code here
When there are many sub-files, the screen will be messy.
But shouldn’t “a-lib.scm” load the relevant “util.scm” file?
Anyway, this is why load is bad.
@chansey97 Not tested, but would using #lang r5rs
combined with (#%require ...)
work differently?