自定义自我引用形式:有用吗?

 我还是看好小棠呀 发布于 2022-12-12 17:47

Lisps经常声明,某些类型是自我评估的.例如,在emacs-lisp数字,"字符串",:关键字 - 符号和一些更多评估自己.

或者,更具体地说:评估表单并再次评估结果会得到相同的结果.

也可以创建自定义自我评估表单,例如

(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)

是否有任何实际用途来定义这些表格,或者这更像是一个深奥的概念?

我想过将"自定义类型"创建为自我评估表单,其中评估可以例如对参数执行类型检查.当我在我的代码中尝试使用这样的类型时,我通常发现它比仅仅使用例如plist更不方便.

*编辑*我再次检查,似乎我混淆了"自我评价"和"自我引用".在emacs lisp中,后一个术语应用于lambda表单,至少在没有词法绑定的上下文中.请注意eq,即使结果是lambda形式,它也永远不会计算为self()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

正如约书亚在他的回答中所说:功能的固定点eval(相对于equal).

1 个回答
  • 您提供的代码未定义一种自我评估表单.一个自我评估表单,当eval作为参数传递时它将返回.让我们仔细看看.首先,有一个函数需要一些参数并返回一个新列表:

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

    新列表将符号my-list作为第一个元素.其余元素是包含符号引用和传递给函数的元素的双元素列表:

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

    现在,这确实给你一个固定点EVAL关于平等的,因为

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

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

    这也是的情况下,自我评价的形式固定点相对于平等,但Common Lisp中,自我评价的形式是一个是一个固定点EVAL相对于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))
        ;...
        ))
    

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

    编译器宏

    虽然通常没有很多用于评估自身(模数等价)关系的表单,但是有一个非常重要的地方,使用非常相似的东西Common Lisp: 编译器宏(强调添加):

    3.2.2.1编译器宏

    compiler-macro-function返回的函数是两个参数的函数,称为扩展函数.要扩展编译器宏,可以通过调用macroexpand挂钩来调用扩展函数,扩展函数作为其第一个参数,整个编译器宏形式作为其第二个参数,以及当前编译环境(或者使用当前词汇环境,如果表单正在由除compile-file之外的其他东西处理)作为其第三个参数.反过来,macroexpand钩子调用扩展函数,其形式为第一个参数,环境为第二个参数.扩展函数的返回值(由macroexpand挂钩传递)可以是相同的形式,也可以是由执行扩展的代码自行决定使用的形式,以代替原始形式.

    Macro DEFINE-COMPILER-MACRO

    与普通的宏不同,编译器宏只能通过返回与原始格式相同的格式(可以通过使用&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))
    

    请注意,这与自我评估表单并不完全相同,因为编译器仍在检查表单是否为汽车具有关联编译器宏的缺点,然后调用该编译器宏函数.形成.但它的相似之处在于形式转向某种形式,而同一形式回归的情况也很重要.

    2022-12-12 17:51 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有