[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [plt-scheme] syntax rules
Quoth Mike T. Machenry:
> i am attempting to learn how to define syntax's in scheme. i decided
> to try to make a toy type system as my first try. the problem i'm
> having is that each identifier in my lambda needs to be put in two
> different places (the assertion and the parameter) and i can't seem to
> do that with a recursive syntax. also my attempt seems to be currying
> the functions so it takes one paramter at a time. i can see how it
> does that but i'm not sure how to do it correctly. also there is a
> shortage of syntax-rules docs on the web, in help-desk, the r5r and in
> the ansi scheme book. does anyone know of a place to read up on this?
It's all there in chapter 11 of the mzscheme language manual, though
that is admittedly not the easiest document to read and use as a
tutorial. :)
> expand this
> (type-lambda ((nunber? foo) (number? bar) (string? baz) un-typed-param)
> (if (= foo bar)
> baz
> un-typed-param))
> [...]
> this is my attempt
> (define-syntax type-lambda
> (syntax-rules ()
> ((_ ((type var) var2 ...) exp1 ...)
> (lambda (var)
> (type-assert type var)
> (type-lambda (var2 ... ) exp1 ...)))
> ((_ (var var2 ...) exp1 ...)
> (lambda (var)
> (type-lambda (var2 ...) exp1 ...)))
> ((_ () exp1 ...)
> (lambda ()
> exp1 ...))
The first problem you'll have is in getting type-assert to be known to
type-lambda at macro-expansion time. There are a couple of ways to do
this; if type-assert is in a separate module, you can require-for-syntax
that module. If type-assert is only used by type-lambda, then you might
want to define it inside type-lambda---like using a "let" to define a
helper function. However, in macros, identifiers bound with "let" are
not accessible in the expansion; you'll need "with-syntax" for that
purpose. That brings us to
(define-syntax type-lambda
(with-syntax ([type-assert (lambda (type? itm)
(unless (type? itm) (error "foo")))])
(syntax-rules ()
[(_ ((type var) var2 ...) exp1 ...)
(lambda (var)
(type-assert type var)
(type-lambda (var2 ... ) exp1 ...))]
[(_ (var var2 ...) exp1 ...)
(lambda (var)
(type-lambda (var2 ...) exp1 ...))]
[(_ () exp1 ...)
(lambda ()
exp1 ...)])))
Next, you're going to run into arity problems. In particular, if the
type-lambda form has multiple arguments, its expansion will be a curried
function that returns a thunk. If I define the function fromk as follows:
(define fromk (type-lambda ([list? l] [string? s] x) (printf "~a~a~a" l s x)))
its expansion (omitting type assertions) will be
#'(lambda (l)
(lambda (s)
(lambda (x)
(lambda () (#%app (#%top . printf) (#%datum . "~a~a~a") l s x)))))
which means that to call it with the arguments lst, str, and num, I have
to write
> ((((fromk lst) str) num))
in order to get it to actually print, which is probably not what you
want. This issue is a little trickier, as you'll need to have the
outer-level lambda in the expansion accept all the arguments at the same
time, but you still want to write your macro recursively. This is a
pretty cool problem that (unfortunately) I don't have time to work on
further, but I suspect that the solution will involve actual computation
during macro expansion, which can be tricky. You'll probably want to
read up on how syntax-case works, for starters. Work on this for a
while, and let us (me) know when you get stuck again. :)
--
-=-Don Blaheta-=-=-dpb@cs.brown.edu-=-=-<http://www.cs.brown.edu/~dpb/>-=-
When your hammer is C++, everything begins to look like a thumb.
--Steve Hoflich, comp.lang.c++