Macros Lisp源代码重写系统

Macros Lisp源代码重写系统,macros,pattern-matching,lisp,elisp,reduction,Macros,Pattern Matching,Lisp,Elisp,Reduction,我想使用已宏扩展的Emacs Lisp代码,并对其进行反宏扩展。我在Emacs论坛上问过这个问题,但没有成功。见: 然而,有人会认为,这种类型的东西,S表达式转换,正是Lisp的拿手好戏。我相信在Lisp中可以像在Emacs Lisp中一样使用defmacro 所以肯定有程序转换系统,或者术语重写系统,可以在这里进行调整 理想情况下,在某些情况下,这样的工具能够直接在defmacro上进行模式查找和替换。然而,即使我必须手动提出特定的搜索和替换模式来添加到转换系统中,拥有这样一个框架仍然是有用

我想使用已宏扩展的Emacs Lisp代码,并对其进行反宏扩展。我在Emacs论坛上问过这个问题,但没有成功。见:

然而,有人会认为,这种类型的东西,S表达式转换,正是Lisp的拿手好戏。我相信在Lisp中可以像在Emacs Lisp中一样使用
defmacro

所以肯定有程序转换系统,或者术语重写系统,可以在这里进行调整

理想情况下,在某些情况下,这样的工具能够直接在
defmacro
上进行模式查找和替换。然而,即使我必须手动提出特定的搜索和替换模式来添加到转换系统中,拥有这样一个框架仍然是有用的

到目前为止的结果摘要:虽然有一些答案探索了有趣的可能性,但目前还没有确定的答案。所以我认为最好还是把这个打开。我将总结一些建议。(我对所有事实上是答案的答案进行了投票,而不是对难度的评论。)

首先,许多人建议考虑只进行扩展的宏的特殊形式,或者如Drew所说:

宏展开(即不展开,然后进行Lisp求值)。 宏扩展是表示还原语义的另一种方式,或 重写

在我看来,目前的领跑者是在phils post,他使用了一种模式匹配工具,这似乎是Emacs特有的:
pcase
。我将对此进行探讨,并将公布我的研究结果。如果其他人对此有想法,请插话

Drew编写了一个名为FTOC的程序,其目的是将Franz Lisp转换为Common Lisp;谷歌搜索发现了一个问题

我发现了一个名为with的通用Lisp包。保罗认为,然而,这可能不够强大,因为它不处理开箱即用的回溯,但可以手动编程。虽然回溯的通用性可能很好,但我不认为在最常用的情况下我需要回溯。)

旁注:一些似乎被引起我最初兴趣的特定应用程序推迟了。(但请注意,在研究中,好的解决方案以最初设想不到的方式得到应用并不罕见。)


因此,本着这种精神,这里有一些关于更改最终应用程序的建议。一个好的解决方案可能会转化为Emacs Lisp的解决方案。(如果能帮你假装我对Emacs Lisp不感兴趣,那我也没问题)。假设我想为clojure或一些常见的Lisp系统编写反编译器,而不是为Emacs Lisp编写反编译器。或者,正如Sylvester的回答所建议的,假设我想通过考虑使用现有的或改进的更简洁的宏来自动重构代码。回想一下,Emacs Lisp曾经没有“何时”或“除非”宏

一般来说,我认为你做不到这一点。lisp宏的扩展是图灵完成的,因此您必须能够预测可能具有任意输入的程序的输出

你可以做一些简单的事情。中带有反引号形式的defmacros在输出形式中非常相似,可能会被检测到。这种启发式可能会让你走很长的路


我不明白的是你的用例。一段代码的宏扩展版本通常仅以编译(或emacs lisp byte compiled)形式出现

30几年前,我用
macrolet
做了类似的事情

(实际上,我使用了
defmacro
,因为我们只有Common Lisp的早期实现,它还没有
macrolet
。但是
macrolet
是正确的使用方法。)

我没有将宏扩展代码转换为它的扩展源代码,但想法基本相同。我想你会遇到一些不同的困难,因为你的翻译离一对一更远

我编写了一个从(当时的)franzlisp到commonlisp的翻译程序,以帮助将大量现有代码移植到Lisp+Prolog机器项目中。Franz Lisp当时只是动态范围,而Common Lisp(通常)是词汇范围

是的,显然有一种通用的方法可以自动翻译Lisp代码(特别是),特别是考虑到它可以生成并计算其他代码,但甚至忽略了这种特殊情况。许多函数非常相似,但存在词汇/动态差异,以及一些看似相似的函数在语义上的显著差异

所有这些都必须从一开始就被理解,并被任何想利用翻译结果的人视为理所当然

尽管如此,仍然可以做很多有用的事情。如果生成的代码是自文档化的,告诉您它是从何而来的等等,那么在生成的上下文中,您可以决定如何处理这个或那个可能很棘手的位(例如,手动重写、从头开始或只是调整它)。在实践中,许多代码很容易从Franz转换为Common,从而节省了大量的重新编程工作

翻译程序是用公共Lisp编写的。它可以交互使用,也可以批量使用。当以交互方式使用时,它实际上提供了一个位于CommonLisp之上的FranzLisp解释器

该程序仅使用宏展开(即,不展开,然后进行Lisp求值)宏扩展是表示还原语义或重写的另一种方式。

输入Franz Lisp代码通过函数定义映射宏进行宏扩展,以生成通用Lisp代码。翻译有问题的代码(在代码中)被标记为描述情况的描述/分析

该计划被称为FTOC。我
(defmacro my-macro-1 ()
  `1)

(defmacro my-macro-2 ()
  `(my-function (my-macro-1)))

(defun my-function (n)
  (* n 100))

(macrolet ((my-macro-1 ()
             `2))
  (flet ((my-function (n)
           (* n 1000)))
    (my-macro-2)))
(defmacro my-macro-2 ()
  ;; capture global bindings of my-macro-1 and my-function-1 by name
  (flet ((my-macro-1-global (form env)
           (funcall (macro-function 'my-macro-1) form env))
         (my-function-global (&rest args)
           ;; hope the compiler can optimize this
           (apply 'my-function args)))
    ;; store them globally in uninterned symbols
    ;; hopefully, no one will mess with them
    (let ((my-macro-1-symbol (gensym (symbol-name 'my-macro-1)))
          (my-function-symbol (gensym (symbol-name 'my-function))))
      (setf (macro-function my-macro-1-symbol) #'my-macro-1-global)
      (setf (symbol-function my-function-symbol) #'my-function-global)
      `(,my-function-symbol (,my-macro-1-symbol)))))