Reputation: 31
#lang racket/base
(module x scribble/text
@(display 123))
It seems like #lang statements are not valid in nested sub-modules, and the expanded module version above is missing something:
error: module: no #%module-begin binding in the module's language
looks like this more or less works, but is there a better way? does scribble do something with output ports that isn't being handled?
#lang racket/base
(module x scribble/text/lang
(#%module-begin
#reader scribble/reader @list{
hi
@(+ 1 456)
}))
Upvotes: 2
Views: 261
Reputation: 29546
First, your code has a redundant #%module-begin
which can be removed.
#lang
does several things -- one is control the semantics of the file
by determining the set of initially imported bindings, and that's
something that the module
form has done before #lang
came up. With
submodules, it became possible to use module
for parts of a file too.
However, #lang
can also determine the reader that parses the file, and
that's not possible to do with submodules, so you're stuck with only one
toplevel #lang
to set the parser for the whole file.
(Sidenote: There is a technical reason for that. A #lang
reader reads
the rest of the file until it reaches an eof
value, so a nested
#lang
would require getting an eof
value before getting the end of
the file, or adding a new kind of eof-like value. That means that it's
a change that should be done carefully -- it's possible to do, of
course, but the need didn't come up often enough. Hopefully it will, in
the future.)
But in your case you don't want a completely new concrete syntax, just
an extension for s-expressions -- and an extension that was chosen to
have a minimal impact on regular code. So in almost all cases it's fine
to just enable the @-form syntax for the whole file, and then use
@-forms where you want it. Since it's just an alternative way for
reading sexprs, you can even use that with module
, leading to this
code that doesn't need to use #reader
:
#lang at-exp racket/base
@module[x scribble/text/lang]{
hi
@(+ 1 456)
}
(require 'x)
One thing that is a bit strange here is using scribble/text/lang
and
not just scribble/text
. Usually, #lang foo
is exactly the same as
(module x foo ...)
after reading the code with foo
s reader. But in
the case of the scribble/text
language there is another difference:
using it as a #lang
makes the semantics of the module body be "output
each thing". The idea is that as a language you'll want to spit out
mostly-text files, but as a library you'll want to write code in it
and do the printout yourself.
Since this code uses module
, using scribble/text
means that you're
not getting the spit-all-out functionality, which is why you need to
explicitly switch to scribble/text/lang
. But you could have instead
just do the spitting yourself using the language's output
, which would
give you this code:
#lang at-exp racket/base
(module x racket/base
(require scribble/text)
(output @list{
hi
@(+ 1 456)}))
(require 'x)
Note that scribble/text
is not used as a language here, since it
doesn't provide enough stuff to be one when used (outside of a #lang
).
(Which you've found out, leading to that redundant #%module-begin
...)
This version is slightly more verbose, but I'm guessing that it makes more sense in your case, since using it for some part of the code means that you want to use it as a library.
Finally, if you really don't want to read the whole file with the @
syntax, only some parts, then the #reader
that you've found is
perfectly fine. (And this is made simple with scribble/text
that
treats lists as concatenated outputs, so you need just one wrapper for
each chunk of text.)
Upvotes: 4