2
votes

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.
1
I'm an expert on neither datalog nor macros but this looks like a hygiene problem. The bindings are probably getting renamed in the background and you'll need to use syntax-case or syntax-parse forms to break hygiene.law-of-fives
@law-of-fives I am using syntax-case. How do I break hygiene with it?Name McChange
you need to use with-syntax to introduce bindings that aren't secretly relabeled by the macro system.law-of-fives
Can you give a complete example? I think I'm wrong about hygiene.law-of-fives
@law-of-fives Just added it.Name McChange

1 Answers

1
votes

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.