【问题标题】:About macro usage which is described in OnLisp关于 OnLisp 中描述的宏用法
【发布时间】:2013-12-12 07:05:31
【问题描述】:

只是不明白用于创建上下文的运算符的宏的描述。 在我看来,如果有绑定,宏是唯一的选择。

这难道不能通过其他方式实现吗? 下面的文字到底是什么意思?

非常感谢。

除了词汇环境之外,还有另一种上下文。在里面 从广义上讲,上下文是世界的状态,包括 特殊变量的值、数据结构的内容和 Lisp 之外的事物状态。构建这种类型的运营商 上下文也必须定义为宏,除非它们的代码体是 被包装在闭包中。上下文构建宏的名称通常 以-开头。这种类型最常用的宏是 可能是打开文件。它的身体是用一个新打开的 文件绑定到用户提供的变量:

(with-open-file (s "dump" :direction :output)
  (princ 99 s))

......

这个操作符显然必须定义为 amacro,因为它绑定了 s。 但是,导致在新上下文中评估表单的运算符 无论如何都必须定义为宏。

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    需要在新环境中执行的表单可以通过两种方式定义:

    • 一个宏,它扩展到为表单准备环境和主体
    • 一个函数,它接受一个在内部执行的函数

    这是不可能的:

    (this-is-some-function-with-some-file-opened (princ 99))
    

    以上是不可能的,因为princ 表单将在函数this-is-some-function-with-some-file-opened 之前执行。参数形式在被调用函数之前执行。然后将这些参数形式的值传递给被调用的函数。

    因此,对于函数式版本,主体形式需要作为函数传递,稍后将使用必要的参数调用该函数。宏变体已经扩展为必要的表单并将主体表单放在其中。

    典型的宏版本:

    (with-open-file (s "dump" :direction :output)
      (princ 99 s))
    

    使用函数的版本:

    (call-with-open-file
       (lambda (s)
         (princ 99 s))
       "dump"
       :direction :output)
    

    在上面一个作为函数传入主体,然后是各种参数。从功能的角度来看,这很好。但是 Common Lisp 在语言标准中没有这个功能。 Common Lisp 提供了构建块(OPENCLOSEUNWIND-PROTECT)和宏 WITH-OPEN-FILE,后者扩展为使用这些构建块的代码。

    缺点是body可能很长,然后参数在底部:

    (call-with-open-file
       (lambda (s)
         (princ 99 s)
         ; 100 more lines here
         )
       "dump"
       :direction :output)
    

    因此,宏版本在代码中被视为更具可读性,因为有关打开的流的所有信息都位于顶部。请注意,将函数放在末尾,而将其他参数放在顶部也不是一个好的选择,因为在 Common Lisp lambda 列表中,我们有这样的规定:位置参数在前,然后是可选参数和关键字参数。

    但在许多库中,我们同时获得了函数和宏。宏只是扩展为函数。

    【讨论】:

    • 但仍然不理解“这显然必须定义为宏。Becatent 绑定 s。但是导致表单在新上下文中求值的运算符无论如何都必须定义为宏。”
    • @user1461328:我试图在上面的答案中解决这个问题,并添加了一些内容。
    • 我想我终于明白意思了。如果运算符创建上下文并在上下文下评估其主体代码,则运算符必须定义为宏。除非,将首先评估正文代码,而不是在上下文中。我对吗?真的谢谢你,雷纳。
    猜你喜欢
    • 1970-01-01
    • 2021-08-28
    • 2014-02-19
    • 2018-03-11
    • 2013-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多