[racket] Defining Syntax in Racket

From: Scott Brown (brown131 at yahoo.com)
Date: Sun Apr 20 10:26:05 EDT 2014

I am trying to write a Definite Clause Grammar syntax for Racklog, analogous to Prolog's DCG extension. Basically, I have created a syntax definition %rule so that: 

(define %sentence (%rule () [() (%noun-phrase) (%verb-phrase)]))

would be redefined as:

(define %sentence (%rel (s0 s1 s) [(s0 s) (%noun-phrase s0 s1) (%verb-phrase s1 s)]))

This code that I have so far works:

#lang racket
(require racklog (for-syntax racket))

;;; Define a rule using DCG notation.
(define-syntax (%rule stx)
  (syntax-case stx ()
    [(_ (v ...) ((a ...) subgoal ...) ...)
     (with-syntax ([gls (for/list ([g (syntax->list #'(((a ...) subgoal ...) ...))]) (length (syntax->list g)))])
       (with-syntax ([rule (append '(%rel) 
                                   (list (append (for/list ([i (in-range (sub1 (apply max (syntax->datum #'gls))))]) 
                                                   (string->symbol (~a "s" i))) '(s) #'(v ...)))
                                   (for/list ([g (syntax->datum #'(((a ...) subgoal ...) ...))])
                                     (cons (append '(s0 s) (first g)) 
                                           (for/list ([sg (rest g)]
                                                      [i (in-range (length (rest g)))])
                                             (append sg (list (string->symbol (~a "s" i))
                                                              (if (= i (sub1 (length (rest g)))) 's 
                                                                  (string->symbol (~a "s" (add1 i))))))))))])

;;; Define a terminal using DCG notation.
(define-syntax (%term stx)
  (syntax-case stx ()
    [(%term (t ...) ...) #'(%rel (x) [((append '(t ...) x) x)] ...)]))

;;; A simple English grammar in DCG notation.
(define %sentence (%rule () [() (%noun-phrase) (%verb-phrase)]))
(define %noun-phrase (%rule () [() (%proper-noun)]
                               [() (%det) (%noun)]
                               [() (%det) (%noun) (%rel-clause)]))
(define %verb-phrase (%rule () [() (%trans-verb) (%noun-phrase)]
                               [() (%intrans-verb)]))
(define %rel-clause (%rule () [() (%dem-pronoun) (%verb-phrase)]))
(define %det (%term [the] [every] [a]))
(define %noun (%term [cat] [bat]))
(define %proper-noun (%term [john] [mary]))
(define %dem-pronoun (%term [that]))
(define %trans-verb (%term [eats]))
(define %intrans-verb (%term [lives]))

;;; Tests
(%which (x) (%sentence x null))
(%which () (%sentence '(a cat eats the bat) null))
(%which (x) (%noun x null))

The problem I am having is that while this works when %rule is included in the same module (as above), when I move %rule and %term into a different module, I get the error "%noun-phrase: unbound identifier in module in: %noun-phrase". I suspect that it is some kind of a namespace issue, or possibly a phase issue.

I have tried rewriting %rule a couple of different ways (one using syntax-rules rather than syntax-case, and another using quasiquote/unquote rather than with-syntax). Neither of which worked. Anyhow, I've spent a lot of time trying to figure this out, and I finally am at the point where I need some help.


Posted on the users mailing list.