如何在Elisp中创建DSL

rej*_*eep 6 emacs macros elisp

我想在Elisp中创建一个DSL,看起来像这样:

(install
 ;; do install
 )

(uninstall
 ;; do uninstall
 )
Run Code Online (Sandbox Code Playgroud)

但是,由于Elisp具有全局命名空间,因此这不是一个好主意.并且像这样的函数前缀是非常难看的.

(package-install
 ;; do install
 )

(package-uninstall
 ;; do uninstall
 )
Run Code Online (Sandbox Code Playgroud)

所以我认为作为妥协,所有命令都可以包含在这样的命令调用中:

(commands
 (install
  ;; do install
  )

 (uninstall
  ;; do uninstall
  )

 ;; ...
 )
Run Code Online (Sandbox Code Playgroud)

但由于我不希望在全局命名空间中安装卸载,我不得不在命令宏中,用例如前缀名替换所有出现的命令,如下所示:

(defmacro commands (&rest body)
  (mapcar
   (lambda (exp)
     (setcar exp (intern (concat "package-" (symbol-name (car exp)))))
     (setcdr exp (list (cons 'progn (cdr exp)))))
   body)
  `(progn ,@body))

(commands
 (install
  ;; do install
  )

 (uninstall
  ;; do uninstall
  )

 ;; ...
 )
Run Code Online (Sandbox Code Playgroud)

这看起来像是一个黑客.如果有任何嵌套命令,它将无法工作.

对于这个有什么好的解决方案还是要破解的方法?

谢谢!

Gil*_*il' 8

本地定义install和朋友怎么样?这不会隐藏标准功能,但它看起来并不像你真正追求的那样.

(defmacro commands (&rest body)
  `(flet ((install (&rest args) (apply 'package-install args))
          (uninstall (&rest args) (apply 'package-uninstall args)))
     ,@body))
Run Code Online (Sandbox Code Playgroud)

当然,您需要flet自动生成该参数列表.你确实需要一个包的元素列表,可能使用(feature-symbols 'package).