Emacs 在宏中使用clojure语法引号时,是否可以关闭符号限定?
我正在从clojure函数生成emacs elisp代码。我最初使用defmacro,但我意识到,由于我要跨平台,并且必须手动将代码评估到elisp环境中,所以我可以同样轻松地使用标准clojure函数。但基本上我所做的是非常宏观的 我这样做是因为我的目标是创建一个DSL,从中我将生成elisp、clojure/java、clojurescript/javascript甚至haskell中的代码 我的“宏”如下所示:Emacs 在宏中使用clojure语法引号时,是否可以关闭符号限定?,emacs,clojure,elisp,Emacs,Clojure,Elisp,我正在从clojure函数生成emacs elisp代码。我最初使用defmacro,但我意识到,由于我要跨平台,并且必须手动将代码评估到elisp环境中,所以我可以同样轻松地使用标准clojure函数。但基本上我所做的是非常宏观的 我这样做是因为我的目标是创建一个DSL,从中我将生成elisp、clojure/java、clojurescript/javascript甚至haskell中的代码 我的“宏”如下所示: (defn vt-fun-3 [] (let [hlq "vt"]
(defn vt-fun-3 []
(let [hlq "vt"]
(let [
f0 'list
f1 '(quote (defun vt-inc (n) (+ n 1)))
f2 '(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8))))]
`(~f0 ~f1 ~f2)
)))
这将生成一个包含两个函数定义的列表——生成的elisp defun和单元测试:
(list (quote (defun vt-inc (n) (+ n 1))) (quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
(vt-inc 4)
--> 5
(ert "vt-inc-test")
--> t
然后,从emacs暂存缓冲区,我利用clomacs导入elisp环境:
(clomacs-defun vt-fun-3 casc-gen.core/vt-fun-3)
(progn
(eval (nth 0 (eval (read (vt-fun-3)))))
(eval (nth 1 (eval (read (vt-fun-3))))))
从这里,我可以运行函数和单元测试:
(list (quote (defun vt-inc (n) (+ n 1))) (quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
(vt-inc 4)
--> 5
(ert "vt-inc-test")
--> t
注意:与所有宏一样,引用和转义的语法非常脆弱。我花了一段时间才找到在elisp中正确评估它的正确方法(整个前缀)
无论如何,正如第一个“let”中出现的“hlq”(高级限定符)所表明的,我想用这个hlq作为任何生成符号的前缀,而不是硬编码它
不幸的是,当我在“f1”上使用标准引号和转义符时,例如:
f1 '(quote (defun ~hlq -inc (n) (+ n 1)))
这将产生:
(list (quote (defun (clojure.core/unquote hlq) -inc (n) (+ n 1)))
(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
换句话说,它用“clojure.core/unquote”代替“~”,这不是我想要的
clojure语法返回引号:
f1 `(quote (defun ~hlq -inc (n) (+ n 1)))
没有这个问题:
(list (quote (casc-gen.core/defun vt casc-gen.core/-inc (casc-gen.core/n) (clojure.core/+ casc-gen.core/n 1))) (quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8)))))
它正确地转义并插入我想要的“vt”(我仍然需要计算出名称的词干,但我并不担心这一点)
问题解决了,对吗?不幸的是,语法引号完全限定了所有符号,我不希望这样,因为代码将在elisp下运行
在使用语法引号(回勾)时,是否有办法关闭符号的限定
在我看来,语法引号更“有能力”这是真的吗?或者你可以通过欺骗手段,使标准引号的行为与语法引号的行为相同吗?如果你不能关闭语法引号的限定,我如何才能使它与标准引号一起工作?我作为defmacro尝试这样做会有什么好处吗
最糟糕的情况是,我必须在生成的elisp上运行正则表达式并手动删除任何限定条件。在使用语法引号时,无法“关闭”符号限定条件。但是,您可以这样做:
(let [hlq 'vt] `(~'quote (~'defun ~hlq ~'-inc (~'n) (~'+ ~'n 1))))
这无疑是相当乏味的。没有语法引号的等价物是:
(let [hlq 'vt] (list 'quote (list 'defun hlq '-inc '(n) '(+ n 1))))
但是,在使用标准quote
作为整个表单的前缀时,无法获得所需的输出
至于使用
defmacro
的问题,据我所知,我不认为使用宏会有任何好处。根据justncon的输入,这是我的最终解决方案。我不得不做一些额外的格式化,以使函数名上的字符串concat正确,但一切都非常类似他建议:
(defn vt-gen-4 []
(let [hlq 'vt]
(let [
f1 `(~'quote (~'defun ~(symbol (str hlq "-inc")) (~'n) (~'+ ~'n 1)))
f2 `(~'quote (~'defun ~(symbol (str hlq "-inc-test")) () (~'should (~'= (~(symbol (str hlq "-inc")) 7) 8))))
]
`(~'list ~f1 ~f2))))
我学到的是:
(defn vt-foo []
(println "(+ 1 1) -> " `(+ 1 1)) --> (clojure.core/+ 1 1)
(println "~(+ 1 1) -> " `~(+ 1 1)) --> 2
(println "~'(+ 1 1) -> " `~'(+ 1 1)) --> (+ 1 1)
)
最后一行是我想要的,第一行是我得到的
(defn vt-gen-3 []
(let [hlq "vt"]
(let
[
f0 'list
f1 `(quote (defun ~(symbol (str hlq "-inc")) (n) (+ n 1)))
f2 '(quote (ert-deftest vt-inc-test () (should (= (vt-inc 7) 8))))
]
`(~f0 ~f1 ~f2)
))
)
;; this strips out any qualifiers like "casc-gen.core/"
(defn vt-gen-3-regex []
(clojure.string/replace (str (vt-gen-3)) #"([\( ])([a-zA-Z0-9-\.]+\/)" "$1" ))