关于OnLisp中描述的宏用法

关于OnLisp中描述的宏用法,lisp,common-lisp,Lisp,Common Lisp,只是不理解用于创建上下文的运算符的宏的描述。 在我看来,如果存在绑定,宏是唯一的选择 这是否不能通过其他方式实现? 下面的文字到底是什么意思 非常感谢 除了词汇环境,还有另一种语境。在 从广义上讲,语境是世界的状态,包括 特殊变量的值、数据结构的内容以及 Lisp之外的事物状态。构建这种类型的 上下文也必须定义为宏,除非它们的代码体是 包装成封闭式。上下文构建宏的名称通常是 以-。这种类型最常用的宏是 可能是打开了文件。其主体将使用新打开的 绑定到用户提供的变量的文件: 这个操作符显然必须定义

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

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

非常感谢

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

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


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

  • 一个宏,它扩展到为窗体准备环境和主体
  • 一个函数,它接受在内部执行的函数
不可能的是:

(this-is-some-function-with-some-file-opened (princ 99))
上述操作是不可能的,因为
princ
表单将在函数
之前执行。这是一个打开了某个文件的函数。参数形式在被调用函数之前执行。这些参数形式的值随后将传递给被调用函数

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

典型的宏版本:

(with-open-file (s "dump" :direction :output)
  (princ 99 s))
使用函数的版本:

(call-with-open-file
   (lambda (s)
     (princ 99 s))
   "dump"
   :direction :output)
在上面的例子中,一个函数作为一个函数在体内传递,然后各种参数随之传递。从功能的角度来看,这很好。但通用Lisp在语言标准中没有此功能。Common Lisp提供了构建块(
OPEN
CLOSE
UNWIND-PROTECT
)和宏
WITH-OPEN-FILE
,该宏扩展为使用构建块的代码

缺点是主体可能较长,然后参数位于底部:

(call-with-open-file
   (lambda (s)
     (princ 99 s)
     ; 100 more lines here
     )
   "dump"
   :direction :output)
因此,宏版本在代码中更具可读性,因为关于打开的流的所有信息都位于顶部。请注意,将函数放在末尾,将其他参数放在顶部也不是一个好选项,因为在常见的Lisp lambda列表中,我们有这样一个选项:位置参数排在第一位,然后是可选参数和关键字参数


但在许多库中,函数和宏都可以得到。宏只是扩展到函数中。

但仍然不理解“这显然必须定义为宏。be causent绑定s。但是,导致表单在新上下文中被计算的运算符无论如何必须定义为宏。”@user1461328:我在上面的回答中尝试解决这一点,加上一些内容,我想我终于明白了意思。如果运算符创建上下文并在上下文下计算其主体代码,则必须将该运算符定义为宏。除非,否则将首先计算主体代码,而不是在上下文中。我说得对吗?真的谢谢你,雷纳。
(call-with-open-file
   (lambda (s)
     (princ 99 s)
     ; 100 more lines here
     )
   "dump"
   :direction :output)