如何在没有括号的情况下在Clojure(脚本)中编写DSL?

dil*_*van 3 dsl clojure racket clojurescript

由于Clojure(Script)是一个Lisp,所有DSL(Domain Specific Languages)的例子都使用括号来编码表达式begin和end(就像Lisp那样).然而,至少另一种Lisp方言(Racket)有许多"括号少"DSL(在Racket中创建语言,DSL1,DSL2)的例子.我可以使用一些特殊的方法来转换:

if (a > 10) { print "Ok!" }    ==>    (if (> a 10) (print "Ok!"))
Run Code Online (Sandbox Code Playgroud)

我想知道是否有一些最佳实践指南或库在Clojure中进行这些转换.或者也许有人将Racket的功能移植到Clojure(我不是Racket用户).Racket用户可以向我指出一些有关如何处理此类DSL的Racket文档吗?

Art*_*ldt 6

Clojure故意没有添加用户可定义的读取器宏.这是用于执行顶级代码转换的功能.Clojure确实包括这些,它们不是用户可定义的,因此它们有固定数量.

一个例子是#_ reader宏,它完全删除下一个表达式.(你可以堆叠它们)

#_#_#_(:println  1) (println 2) (println 3) (println 4)
4
Run Code Online (Sandbox Code Playgroud)

您可以做的是定义标记文字,它解决了许多相同的问题,尽管它们并非真正用于定义外部DSL.大多数情况下,您将拥有一个顶级dsl-start宏,然后您不必使用()超出初始符号周围的任何s.有限制,您在语言中提供的内容必须包含可读表达式(符号,地图,矢量,列表等)

(with-my-special-language
   if (a > 10) { print "Ok!" }
   if (a > 42) { print "Even Better!" }
)
Run Code Online (Sandbox Code Playgroud)

如果你真的想避免()将这两个暴露给编写这段代码的人,你可以将该代码读入一个字符串,添加()你的自己,然后评估它.这样直接访问读者非常方便.