lisp - 自定义自引用表格 : Useful?

标签 lisp elisp

Lisps 经常声明,某些类型是 self 评估的。例如。在 emacs-lisp 中,数字、“字符串”、:keyword-symbols 和其他一些 self 评估。

或者,更具体地说:评估表单并再次评估结果给出相同的结果。

也可以创建自定义的 self 评估表格,例如

(defun my-list (&rest args) 
  (cons 'my-list (mapcar (lambda (e) (list 'quote e)) args)))

(my-list (+ 1 1) 'hello)
  => (my-list '2 'hello)

(eval (my-list (+ 1 1) 'hello))
  => (my-list '2 'hello)

定义此类形式是否有任何实际用途,或者这更像是一个深奥的概念?

我想创建“自定义类型”作为自评估形式,其中评估可以例如对参数执行类型检查。当尝试在我的代码中使用这些类型时,我通常发现它与简单地工作相比很不方便,例如虽然有 plists。

*edit* 我又查了一下,好像把“ self 评价”和“ self 引用”搞混了。 In emacs lisp the later term was applied to the lambda form ,至少在没有词汇绑定(bind)的上下文中。请注意,lambda 形式永远不会对自身求值 (eq),即使结果是 equal

(setq form '(lambda () 1))              ;; => (lambda () 1)
(equal form (eval form))                ;; => t
(equal (eval form) (eval (eval form)))  ;; => t
(eq form (eval form))                   ;; => nil
(eq (eval form) (eval (eval form)))     ;; => nil

正如 Joshua 在他的回答中所说:eval 函数的不动点(相对于 equal)。

最佳答案

您提供的代码没有定义一种 self 评估形式。当作为参数传递时 eval 将返回的 self 评估形式。让我们仔细看看。首先,有一个函数接受一些参数并返回一个新列表:

(defun my-list (&rest args) 
  (cons 'my-list (mapcar (lambda (e) (list 'quote e)) args)))

新列表的第一个元素是符号my-list。其余元素是包含符号 quote 和传递给函数的元素的双元素列表:

(my-list (+ 1 1) 'hello)
;=> (my-list '2 'hello)

现在,这确实给了你一个 fixed point对于 eval 关于 equal,因为

(eval (my-list (+ 1 1) 'hello))
;=> (my-list '2 'hello)

(eval (eval (my-list (+ 1 1) 'hello)))
;=> (my-list '2 'hello)

自求值形式也是equals的不动点,但在Common Lisp中,自求值形式是eval<的不动点/strong> 关于 eq(或者可能是 eql)。

指定自评估表单的语言的要点实际上是定义评估者必须使用表单做什么。从概念上讲,eval 的定义如下:

(defun self-evaluating-p (form)
  (or (numberp form)
      (stringp form)
      (and (listp form)
           (eql 2 (length form))
           (eq 'quote (first form)))
      ; ...
      ))

(defun eval (form)
  (cond
    ((self-evaluating-p form) form)
    ((symbolp form) (symbol-value-in-environment form))
    ;...
    ))

关键不是 self 评估形式是评估为等价(对于某些等价关系)值的形式,而是 eval 不需要做任何工作的形式。

编译器宏

虽然对自身求值(取模某些等价)关系的形式通常没有太多用途,但有一个非常重要的地方使用了与 Common Lisp 非常相似的东西:compiler macros (强调):

3.2.2.1 Compiler Macros

The function returned by compiler-macro-function is a function of two arguments, called the expansion function. To expand a compiler macro, the expansion function is invoked by calling the macroexpand hook with the expansion function as its first argument, the entire compiler macro form as its second argument, and the current compilation environment (or with the current lexical environment, if the form is being processed by something other than compile-file) as its third argument. The macroexpand hook, in turn, calls the expansion function with the form as its first argument and the environment as its second argument. The return value from the expansion function, which is passed through by the macroexpand hook, might either be the same form, or else a form that can, at the discretion of the code doing the expansion, be used in place of the original form.

Macro DEFINE-COMPILER-MACRO

  • Unlike an ordinary macro, a compiler macro can decline to provide an expansion merely by returning a form that is the same as the original (which can be obtained by using &whole).

举个例子:

(defun exponent (base power)
  "Just like CL:EXPT, but with a longer name."
  (expt base power))

(define-compiler-macro exponent (&whole form base power)
  "A compiler macro that replaces `(exponent base 2)` forms
with a simple multiplication.  Other invocations are left the same."
  (if (eql power 2)
      (let ((b (gensym (string '#:base-))))
        `(let ((,b ,base))
           (* ,b ,b)))
      form))

请注意,这与自评估表单不太一样,因为编译器仍在检查表单是否为 cons,其 car 具有关联的编译器宏,然后调用该编译器宏与表格一起发挥作用。但它的相似之处在于表单转到某事并且相同表单返回的情况很重要。

关于lisp - 自定义自引用表格 : Useful?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26791876/

相关文章:

用于人工智能的 Lisp 和 Prolog?

emacs - 不能写大写M

python - 使用Hy宏生成Python代码

javascript - 如何使用 Ramda 将代码从 Lisp(MIT Schema)翻译成 JavaScript?

emacs - 保存时自动字节编译

emacs - 如何获得 Emacs 的背景类型?例如 'light or ' 暗

emacs - 如何在 emacs org-mode 中将函数限制为子树?

lisp - 如何将 find-if 与带参数的谓词一起使用

emacs - 重新映射 Emacs 命令

emacs - Emacs lisp 中的 "exec"?