关于OnLisp中描述的宏用法

时间:2013-12-12 07:05:32

标签: lisp common-lisp

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

这是否通过其他方式无法实现? 下面的文字到底意味着什么?

非常感谢。

  

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

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

...

  

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

1 个答案:

答案 0 :(得分:6)

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

  • 一个宏,它扩展到环境的准备和形式的主体
  • 一个函数,它接受一个在
  • 中执行的函数

这是不可能的:

(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,它们扩展为使用构建块的代码。

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

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

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

但在许多图书馆中,我们同时获得了功能和宏。宏只是扩展到函数中。