@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?