[plt-scheme] Getting Serious with Learning Macros

From: Doug Williams (m.douglas.williams at gmail.com)
Date: Wed Sep 16 13:56:38 EDT 2009

Thanks for all the pointers. I have some reading to do.

Ryan,
I'll let you know how it works out.

Doug

On Wed, Sep 16, 2009 at 11:52 AM, Ryan Culpepper <ryanc at ccs.neu.edu> wrote:

> You've essentially described the motivation for the new 'syntax/parse'
> library. It has an enhanced pattern language for specifying syntax and
> abstraction mechanisms for defining syntactic classes. I've just committed a
> quick start introduction with examples in the documentation.
>
> I'd be very interested in hearing your questions, difficulties, and
> successes using syntax/parse.
>
> Another thing you might find helpful is my (rough, incomplete) guide to
> common macro patterns:
>  http://www.ccs.neu.edu/home/ryanc/macro-patterns/
>
> Ryan
>
>
> Doug Williams wrote:
>
>> I'm finally getting serious about using complex macros for (properly)
>> parsing and processing domain specific languages in PLT Scheme. To date, I
>> have just been using syntax-rules to do the minimum parsing needed to
>> break
>> out the basic elements of a construct and generate code that passes them
>> to
>> the code that does the real work at run-time. This is relatively easy to
>> write, but pretty much limits error messages to 'bad syntax', which isn't
>> real useful. But, I haven't found any really good tutorial material to
>> help
>> me get started.
>>
>> So first, can anyone point me to some good material to get started with
>> syntax-case, define-for-syntax, and so on for doing this right? I've
>> gotten
>> started by looking at things like package.ss (in the scheme collection)
>> that
>> have some complex macros.
>>
>> An example of what I would like to do is the define-rule macro in the
>> inference collection.
>>
>> Here is a contrived example of a forward-chaining rule:
>>
>> (define-rule (test-rule-1 test-rule)
>>    (class1 ?a b c)
>>    ?class2 <- (class2 ?a b c)
>>    (or (and (class3 ?a b c)
>>             (class4 ?a b c))
>>        (class5 ?a b c))
>>  ==>
>>    (retract ?class2)
>>    (printf "a = ~s~n" ?a))
>>
>> And, here is an example of a backward-chaining rule:
>>
>> (define-rule (example-rule ancestor-rules)
>>    (ancestor ?x >y)
>>  <==
>>    (ancestor ?x ?z)
>>    (ancestor ?z ?y))
>>
>> In the current (not so good) implementation, the define-rule macro just
>> breaks the rule clauses into goal clauses, pattern clauses, and action
>> expressions using <== and >== as delimiters. Then, it just passes those
>> raw
>> chunks in the run-time code to actually parse and process them.
>>
>> I would like to do is to do all of the parsing and checking at expansion
>> time and provide decent error messages. So, at expansion time, I'd like to
>> (1) parse out the clauses, (2) check the syntax of the goal and pattern
>> clauses, (3) normalize the form of the pattern clauses to (or (and .
>> atomic-patterns) ...), and (4) generate the appropriate code. (Note that
>> the
>> action expressions are 'just code' that will be generated into a
>> procedural
>> object and 'checked' that way.) I am comfortable with (1) and (4) - at
>> least
>> with syntax-rules - and I have a working version using syntax-case with
>> error checking at that level (e.g., the rule name must be an identifier;
>> there can't be multiple <== or ==>; if both <== and ==> are present, they
>> must be in that order). I can do (2) in run-time code, but don't know how
>> to
>> convert that into expansion-time code - maybe it's easy, maybe not.
>> Finally,
>> (3) is some pretty complex run-time code with several mutually recursive
>> procedures doing the normalization. I don't even know where to start doing
>> this (in something other than brute force pattern matching with
>> syntax-rule/syntax case, but there are several dozens of cases and there
>> has
>> to be a better way).
>>
>> So, can someone point me in the right direction to get started? Good
>> examples in the current PLT Scheme code base would work.
>>
>> And, just for the curious, here is a real example of a forward-chaining
>> rule
>> to show what they can look like.
>>
>> ;;; If a cell is numbered, remove that number from any other cell in the
>> ;;; same row, col, or box.
>> (define-rule (rule-5 sudoku-rules)
>>    (cell ?row ?col ?box ?value : (number? ?value))
>>    cell-1 <- (or (cell ?row-1 : (= ?row-1 ?row)
>>                        ?col-1 : (not (= ?col-1 ?col))
>>                        ?box-1
>>                        ?value-1 : (and (pair? ?value-1)
>>                                        (memv ?value ?value-1)))
>>                  (cell ?row-1 : (not = (= ?row-1 ?row))
>>                        ?col-1 : (= ?col-1 ?col)
>>                        ?box-1
>>                        ?value-1 : (and (pair? ?value-1)
>>                                        (memv ?value ?value-1)))
>>                  (cell ?row-1
>>                        ?col-1
>>                        ?box-1 : (and (= ?box-1 ?box)
>>                                      (or (not (= ?row-1 ?row)
>>                                          (not (= ?col-1 ?col))))
>>                        ?value-1 : (and (pair? ?value-1)
>>                                        (memv ?value ?value-1))))
>>  ==>
>>    (replace ?cell-1 `(cell ,?row-1 ,?col-1 ,?box-1 ,(delete ?value
>> ?value-1))))
>>
>> As always, thanks in advance for any advice, directions, mentoring, ...
>> Doug
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> _________________________________________________
>>  For list-related administrative tasks:
>>  http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20090916/4124cdaa/attachment.html>

Posted on the users mailing list.