Talk given at: | EuroLisp Symposium 2009 |
---|---|
By: | Michele Simionato |
Date: | 2009-05-28 |
The easy things about the R6RS module system
Explicit phasing and the tower of meta-levels
Porting libraries between different R6RS implementations
Who am I?
A hobbyist Scheme programmer
$ cat my-lib.sls # in most R6RS implementations
#!r6rs
(library (my-lib)
(export a b)
(import (rnrs)); standard R6RS bindings
(define a 42)
(define b 0)
(display "my-lib instantiated!\n")
)
;; import it as (import (my-lib))
;; be careful with the names!
how to map libraries to the file system is unspecified!
(import (rnrs) (my-lib))
(display (+ a b)) ;=> 42
import with a prefix:
(import (rnrs) (prefix (my-lib) my-lib:))
(display my-lib:a) ;=> 42
import only a specific sets of names:
(import (rnrs) (only (my-lib) a))
(display a) ;=> 42
other easy features
renaming a set of identifiers:
(import (rnrs) (rename (my-lib) (a ml-a)))
(display ml-a) ;=> 42
excluding a set of identifiers:
(import (rnrs) (except (my-lib) a))
(display b) ;=> 0
$ cat compat.mzscheme.sls
#!r6rs
(library (aps compat)
(export printf format pretty-print)
(import (rnrs) (only (scheme) printf format pretty-print)))
$ cat compat.ypsilon.sls
(library (aps compat)
(export printf format pretty-print)
(import (rnrs) (core))
(define (printf format-string . args)
(display (apply format format-string args))))
They are not so scary ...
A simple example:
#!r6rs
(library (show)
(export show)
(import (rnrs) (only (aps compat) printf))
(define-syntax show
(syntax-rules ()
((_ x) (printf "~a=~a\n" 'x x)))))
99.9% of times there are no problems with syntax-rules macros:
> (import (show))
> (define a 1)
> (show a)
a=1
I will show an issue with a second order syntax-rules macro later on
> (let ()
(define a 42)
(define-syntax m (lambda (x) a))
m)
error: identifier a out of context
(let ()
(define a 42) ; run-time
(define-syntax m (lambda (x) a)) ; macro-def-time
m)
One must be careful not to mix expand-time and run-time
$ mzscheme # or larceny
> (define a 42)
> (let-syntax ((m (lambda (x) a))) m)
reference to undefined identifier: a
but
$ ikarus # or ypsilon
> (define a 42)
> (let-syntax ((m (lambda (x) a))) m)
42
Phase separation is not ubiquitous; for instance Guile 1.8 (or Emacs Lisp) have no phase separation:
guile> (let ()
(define a 42)
(define-macro (m) a)
(m))
42
(the next version of Guile will have phase separation and some support for R6RS Scheme).
Put the helper object (value, function, macro) in a different module and import it at expand time
> (import (for (my-lib) expand))
> (let-syntax ((m (lambda (x) a))) m)
42
Not really, since there are a few R6RS surprises ...
An example:
(import (for (only (my-lib) a) expand))
(display (let-syntax ((m (lambda (x) a))) m))
(display a)
Fasten your seatbelts now ...
we saw that the right hand side of macro definition refers to names which are one phase (meta-level) up
(define-syntax macro ; meta-level 0
(lambda (x) ; meta-level 1
(syntax-case x (literals ...) ; meta-level 1
(pattern ; meta-level 1
fender ; meta-level 1
#'template)))) ; meta-level 0
inside a template one goes back one meta-level
(import (for (only (my-lib) a) (meta 2))
(for (only (my-lib) b) (meta 1)))
(define-syntax m1 ;; level 0
(lambda (x1) ;; level 1
(define-syntax m2 ;; level 1
(lambda (x2) a)) ;; level 2
(+ m2 b))) ;; level 1
(display ;; level 0
m1 ;; level 1
) ;; level 0
(define-syntax very-static-table
(syntax-rules ()
((_ (name value) ...)
(syntax-rules (<names> name ...)
((_ <names>) '(name ...))
((_ name) value) ...))))
(define-syntax color
(very-static-table (red 0) (green 1) (blue 2)))
(display (color <names>)) ;=> (red green blue)
(display (color red)) ;=> 0
(define-syntax very-static-table ;; level 0
(syntax-rules () ;; level 1
((_ (name value) ...) ;; level 1
(syntax-rules (<names> name ...) ;; level 0
((_ <names>) ;; level 0
'(name ...)) ;; level -1
((_ name) ;; level 0
value) ;; level -1
...))))
Needs (import (for (only (rnrs) quote) (meta -1)))
(import (rnrs) (for (rnrs) (meta -1))
(for (sweet-macros helper1) (meta -1) (meta 0) (meta 1)))
Such implementations do not need to worry about the Dark Tower. I think they will have a great future!
You get the worse of two worlds: writers of portable code
Porting macro-rich R6RS libraries can be a rather heavy task ...
I have found many bugs in different R6RS implementations while porting my sweet-macros library:
All fixed within hours!
and of course in the R6RS document
This work would not have been possible without the help of
and many others. Thank you!