Search code examples
macroslispracketdataloghygiene

Racket macros not working


I've never used Racket's macro system before so forgive my ignorance. I'm trying to dynamically define rules in Racket's Datalog system, basically like this:

(datalog rules (! (:- c a b)))

If I put something like this into the code directly, all is well. However, I want to dynamically generate these rules. With regular functions I would just do something like this:

(datalog rules (! (apply :- conclusion premises)))

But datalog, ! and :- are all macros, making this impossible.

My solution was to write this macro:

(define-syntax (make-rule stx)
  (syntax-case stx ()
    ((_ premises conclusion)
      #`(datalog rules (! (:- ,conclusion ,@(map (lambda (x) `,x) premises)))))))

Which is then called like this:

(make-rule '(a b) 'c)

However while this does run, querying the Datalog database renders nothing when both a and b are true.

I tried double quoting the syntax object so I could see just what was getting output, and it's this:

'(datalog rules (! (:- c a b)))

So... Exactly what should and does work if I just type it directly in my code! What is going on here? Is this some sort of hygenic macro thing? I really have no idea.

Thanks!

Edit: Here is a complete runnable example of the problem.

#lang racket

(require datalog)

(define rules (make-theory))

(define-syntax (make-rule stx)
  (syntax-case stx ()
    ((_ premises conclusion)
       #`(datalog rules (! (:- ,conclusion ,@(map (lambda (x) `,x) premises)))))))

(make-rule '(a b) 'c)
(datalog rules (? c)) ;;Does not work.

(datalog rules (! (:- c a b)))
(datalog rules (! a) (! b))
(datalog rules (? c)) ;;Works.

Solution

  • OK I think I have it for you. It was not a hygiene problem.

    #lang racket
    (require datalog)
    
    (define rules (make-theory))
    
    (define-syntax (make-rule stx)
      (syntax-case stx ()
        ((_ (ps ...) c)
         #'(datalog rules (! (:- c ps ...))))))
    
    (datalog rules (! a) (! b))
    (make-rule (a b) c)
    (datalog rules (? c))
    

    The problem is with the quoting/unquoting. Here I just modified the template to accept the form you're giving it. Again I'm not really understanding the datalog language but this gives the same output as what you said "works" in your example.