[plt-scheme] re: Shriram Krishnamurthi's "automaton" macro from "Swine before Perl"
From: ian barland (refugee from reality) (ian at cs.rice.edu)
Date: Mon Nov 8 10:54:43 EST 2004 |
|
Hi Chris --
Looks like the immediate cause is that you refer to "new-state" without
using an ellipsis. (The macro doesn't know which particular new-state you're
trying to test against.)
>
> [(_ init-state
> (state : (cndn -> new-state) ...) ...)
> (letrec ([state (lambda (stream)
> (or (and (empty? stream)
> (eq? new-state #f)) ; <-- which new-state?
> (case (first stream)
> [(cndn)
> (new-state (rest stream))]
> ...
> [else false])))]
> ...)
> init-state)]))
>
You want to move your test for #f from the entire-current-state level
to within the individual transition cases.
I think what you were trying would have to be:
(letrec ([state (lambda (stream)
(if (empty? stream) ; Discuss below.
false
(case (first stream)
[(cndn)
(if (empty? (rest stream)) ; No more inputs?
(eq? new-state false) ; next state exists?
(new-state (rest stream)))] ; else proceed
...
[else false])))]
...)
init-state)
...Hmm, that rubs the wrong way though, to check for empty stream
in two different places: at the top-level, and then checking (rest stream)
before recurring. Yuck.
Instead, if you are happy with indicating acceptance by saying
"the automaton must end in a state with no outgoing transitions"
(like the example), then this will work:
(define-syntax automaton
(syntax-rules (-> :)
[(automaton init-state
(state : (cndn -> new-state) ...) ...)
(letrec ([state (lambda (stream)
(if (empty? stream) ; No more inputs?
(empty? '(new-state ...)) ; In a terminal state?
(case (first stream) ; Proceed..
[(cndn)
(new-state (rest stream))]
...
[else false])))]
...)
init-state)]))
I was about to say this feels hackish -- using quote to
create '(new-state ...), which feels like it's back up on the syntax level,
asking if the macro pattern has matched any arguments.
But I guess it's actually fine -- it's just creating a list of next-states,
so no problem asking if that's empty.
This forces your final-state to be a sink though. A more complete sol'n
would be to augment the macro with a keyword for final-states (which
can then be allowed as intermediate states as well).
But in that case, I don't see an easy way to use
this letrec solution any more: there wouldn't be just one
pattern states, but there'd be two patterns, handled in separate
branches of syntax-rules, and so a single letrec doesn't seem to work.
...But I'm newer to macros, so maybe I'm missing something;
if somebody does have a letrec sol'n once you've added a final-state
keyword, I'd be interested in seeing it!
Cheers,
ian
> From: "Chris Wright" <wrightca at hotmail.com>
> To: plt-scheme at list.cs.brown.edu
> Date: Mon, 08 Nov 2004 21:50:22 +1100
> Subject: [plt-scheme] Shriram Krishnamurthi's "automaton" macro from "Swine b
> efore Perl"
>
> Hi.
>
> I think I understand Shriram's macro:
>
> (define-syntax automaton
> (syntax-rules (-> :)
> [(_ init-state
> (state : (cndn -> new-state) ...) ...)
> (letrec ([state (lambda (stream)
> (or (empty? stream)
> (case (first stream)
> [(cndn)
> (new-state (rest stream))]
> ...
> [else false])))]
> ...)
> init-state)]))
>
> (define a
> (automaton init
> (init : (c -> loop))
> (loop : (a -> loop)
> (d -> loop)
> (r -> end))
> (end : )))
>
> In use:
>
> Welcome to DrScheme, version 208.
> Language: Pretty Big (includes MrEd and Advanced).
> >(a '(c a r))
> #t
> >(a '(c d a r))
> #t
> >(a '(c x))
> #f
>
> but:
> >(a '(c a d a))
> #t
>
>
> As an exercise, I thought I'd try seeing if I could make it check that when
> the stream is empty, new-state is null, and I'm having trouble with my
> ellipses!
>
> (define-syntax automaton
> (syntax-rules (-> :)
> [(_ init-state
> (state : (cndn -> new-state) ...) ...)
> (letrec ([state (lambda (stream)
> (or (and (empty? stream)
> (eq? new-state #f))
> (case (first stream)
> [(cndn)
> (new-state (rest stream))]
> ...
> [else false])))]
> ...)
> init-state)]))
>
> (define a
> (automaton init
> (init : (c -> loop))
> (loop : (a -> loop)
> (d -> loop)
> (r -> end))
> (end : #f)))
>
> This gives:
>
> syntax: too few ellipses for pattern variable in template in: new-state
>
> (And I'm not even sure that the test (eq? new-state #f) will do what I want
> it too, but that's a separate issue)
>
>
> Could someone help me understand this?
>
> Thanks very much.
>
> Chris Wright