[gambit-list] Macros in Black Hole

Per Eckerdal per.eckerdal at gmail.com
Fri Feb 5 04:51:50 EST 2010


5 feb 2010 kl. 01.25 skrev Álvaro Castro-Castilla:

> Hi!
> 
> I'm new to this list and also to Gambit. I'm trying to get used to it, and I like most of the things very much (taking into account that I'm new to Scheme).
> 
> I'm trying to use Black Hole module system, and I've found out something that I don't understand how it works or what I'm doing wrong.
> 
> If you have this scheme file, called for example "bhtest.scm"
> 
> (load "/usr/lib/modules/build")
> (import (std srfi/14))
> 
> 
> and you try to execute it with "gsc -i bhtest.scm", you'll get this:
> 
> *** ERROR IN "blackhole.scm"@3.2 -- Unbound variable: import

I think a clarification to why this doesn't work (and the same code in the REPL does) would be helpful not only to understand Black Hole, but also other similar issues.

When you type the load expression into the REPL, Gambit will load Black Hole, and Black Hole will override two hooks, ##expand-source and c#expand-source. These two functions are by default the identity function (that is, (lambda (x) x)). ##expand-source is called every time code is evaluated, and Black Hole adds its macro expander there.

After loading BH in the REPL, BH's macro expander will be there, so in the next line, when you type (import ...), BH will recognize it and take proper action.

However, when loading a file containing both (load "/usr/lib/modules/build") and (import (std srfi/14)), what will happen is that Gambit will parse the whole file, then call ##expand-source on the resulting s-expression, then eval that expression. Black Hole will get loaded, but when it is, the whole file's code will already have been macro-expanded, so the import will be seen as a normal procedure call, which obviously won't work.

This is a kind problem that many people that are new to Gambit (and probably other implementations of Scheme as well) seem to have. The difference between typing something into the REPL, load-ing a file with the same expressions, or include-ing a file is not very easy to understand at first.

For me, it helped to think like this (it's not entirely correct, but kind of): It's possible to implement both load and include, assuming that read-file is a function that reads a file's s-exps and wraps them in a begin, as an example would bhtest.scm yield (begin (load "/usr/lib/modules/build") (import (std srfi/14)))

(define (load filename)
  (eval (read-file filename)))

(define-macro (include filename)
  (read-file filename))


The main reason why you're not supposed to have a load expression inside of your scheme files is that I have tried hard to design BH in a way that makes it easy to share code. Having a load expression in the beginning of each file would ruin that, because everyone will not have BH installed at the same place. Also, this ensures that very simple code is kept very simple and clean, yet it will scale and still be useful in larger applications. An example of a typical BH module is a simple FIFO queue library that I have written:

http://github.com/pereckerdal/blackhole-libs/blob/master/ds/queue.scm

It's possible to import it like this: (import "http://github.com/pereckerdal/blackhole-libs/raw/master/ds/queue.scm")


This mail turned out somewhat messy, I hope it helps.

/Per




More information about the Gambit-list mailing list