[plt-scheme] MzScheme as embedded engine for LilyPond ?
Hi there,
I am one of the main authors of the music typesetting package LilyPond
(http://lilypond.org). LilyPond derives much from its flexibility and
power from the fact that embeds a Scheme interpreter.
Unfortunately, the interpreter of our choice --GUILE-- leaves a lot to
be desired. In particular, it's slow, and development is
withering. The last stable release (GUILE 1.6) is more than two years
old.
I'm looking into alternative Scheme interpreters, and the most obvious
alternative is the PLT Scheme suite, in particular the MzScheme
interpreter, due to its active development, excellent documentation,
and high execution speed.
I've read through the documentation and source-code, and that raised
some questions with me. I would be grateful if you could answer some
of them for me.
* How well is embedding MzScheme supported? I've read "Inside PLT
MzScheme". Am I correct that there is no way to add "coded" types to
MzScheme?
In GUILE, you can add native types, called smobs, to the
interpreter. All that is needed, is specifying C functions for
- GC marking the object
- freeing the object
- printing the object
- comparing the object
LilyPond uses this extensively, it contains 22 different smob types.
All major classes in the program have been smobbified.
* Can I force symbols to be conservatively GC'd? Inside lilypond
source code, we have a macro ly_symbol2scm(), eg.
SCM foo = bar();
if (foo == ly_symbol2scm ("bla-bla"))
..
ly_symbol2scm interns "bla-bla", and stores the outcome, so that
only the first invocation of ly_symbol2scm() is costly. Of course,
this only works if the actual SCM isn't moved around.
(I believe the MzScheme term for SCM is Scheme_Object*)
* Is there a possibility to read a single expression precisely off an
input stream?
In LilyPond input files, you can escape to Scheme, using # , for
example:
\score { #(make-music 'NoteEvent) }
here, the lexer gives control to the Scheme interpreter when it
reaches # . The Scheme interpreter reads up to the ) and evals the
result. The lexer then continues at the )
Is this somehow possible with MzScheme?
* Is there support for read extensions? We have a special feature,
that allows us to parse LilyPond code inside one of these embedded
Scheme fragments, for example
(make-sequential-music #{ \notes { c4 d8 } #} )
will pass "\notes { c4 d8 }" to a function that we hooked up with
#{
* Is there support for stack-traces/source annotation? If I make an
error in GUILE in debug mode, I get
byrd:~/usr/src/lilypond$ guile --debug b.scm
Backtrace:
In unknown file:
?: 0* [primitive-load "b.scm"]
In b.scm:
9: 1* [Y]
7: 2 [x 0]
3: 3 [0]
b.scm:3:3: In expression (a):
b.scm:3:3: Wrong type to apply: 0
a nice stack trace, with line/column numbers of the calling points.
How do I get that in MzScheme? I've understood that this is only
supported in DrScheme, but I need to switch between both modes on
the fly. In other words,
lilypond --debug foo.ly
would use the MzScheme with locations, and
lilypond foo.ly
would use the non-debugging version. Is this possible at all?
* Is there support for doc strings and self-documentation? In
LilyPond, almost all coded subroutines come with docstrings, and
would show up if you did
(apropos "ly:music?")
* MzScheme doesn't support OS level threads. Will this ever be
supported?
I have the impression that the current trend in chip design is not
to go faster, but to go parallel (cf: HyperThreading and multi-core
chips). Of course, this only helps if your app uses OS level
threads.
Of course if any of these is not supported, then would these features
stand a chance of being added/incorporated? I'm willing to work on
this or transplant the appropriate code from GUILE.
--
Han-Wen Nienhuys | hanwen at xs4all.nl | http://www.xs4all.nl/~hanwen