【发布时间】:2018-03-22 00:44:29
【问题描述】:
我以前从未使用过 Racket 的宏系统,所以请原谅我的无知。我正在尝试在 Racket 的 Datalog 系统中动态定义规则,基本上是这样的:
(datalog rules (! (:- c a b)))
如果我直接将这样的内容放入代码中,一切都很好。但是,我想动态生成这些规则。使用常规功能,我会做这样的事情:
(datalog rules (! (apply :- conclusion premises)))
但是datalog、! 和:- 都是宏,所以这不可能。
我的解决方案是编写这个宏:
(define-syntax (make-rule stx)
(syntax-case stx ()
((_ premises conclusion)
#`(datalog rules (! (:- ,conclusion ,@(map (lambda (x) `,x) premises)))))))
然后这样调用:
(make-rule '(a b) 'c)
但是,虽然这确实运行,但当 a 和 b 都为 true 时,查询 Datalog 数据库不会呈现任何内容。
我尝试对语法对象进行双引号,这样我就可以看到输出的内容,就是这样:
'(datalog rules (! (:- c a b)))
所以...如果我直接在我的代码中输入 应该 和 究竟是什么工作!这里发生了什么?这是某种卫生的宏观事物吗?我真的不知道。
谢谢!
编辑:这是该问题的完整可运行示例。
#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.
【问题讨论】:
-
我既不是数据记录也不是宏专家,但这看起来像是一个卫生问题。绑定可能会在后台重命名,您需要使用
syntax-case或syntax-parse表单来破坏卫生。 -
@law-of-fives 我正在使用语法大小写。我该如何打破卫生习惯?
-
您需要使用
with-syntax来引入宏系统不会秘密重新标记的绑定。 -
你能举一个完整的例子吗?我认为我在卫生方面错了。
-
@law-of-fives 刚刚添加。
标签: macros lisp racket datalog hygiene