使用#aka read-macro

Mar*_*ark 2 lisp common-lisp reader-macro

由Doug Hoyte阅读的书"Let Over Lambda",我发现了以下对#.符号的描述,即read-macro:

使用COMMON LISP内置的基本读取宏是#.读取时间eval宏.此读取宏允许您将对象嵌入到您读取的无法序列化的表单中,但可以使用一些lisp代码创建.

它来自第4章,本书的大部分内容可以在这里找到:http: //letoverlambda.com/index.cl/toc

这是本书中的示例,显示了每次都可以以不同的方式读取相同的表达式:

* '(football-game
     (game-started-at
       #.(get-internal-real-time))
     (coin-flip
       #.(if (zerop (random 2)) 'heads 'tails)))

(FOOTBALL-GAME
  (GAME-STARTED-AT 187)
  (COIN-FLIP HEADS))

* '(football-game
     (game-started-at
       #.(get-internal-real-time))
     (coin-flip
   #.(if (zerop (random 2)) 'heads 'tails)))

(FOOTBALL-GAME
  (GAME-STARTED-AT 309)
  (COIN-FLIP TAILS))
Run Code Online (Sandbox Code Playgroud)

接下来,作者演示了一些硬核技巧,用#宏创建变体.

因此,事实证明它#'也是某种读取宏,它通常在表示函数名称的符号之前使用.但这是否必要,他的工作到底是什么?

我可以在有#'或没有它的情况下为高阶函数添加符号:

CL-USER> (defun test nil t)
TEST
CL-USER> (funcall #'test)
T
CL-USER> (funcall 'test)
T
Run Code Online (Sandbox Code Playgroud)

取得同样的成功.

Rai*_*wig 7

您可以通过两种方式调用函数的全局定义:

CL-USER> (defun test nil t)
TEST
CL-USER> (funcall #'test)
T
CL-USER> (funcall 'test)
T
Run Code Online (Sandbox Code Playgroud)

但看到这个:

CL-USER 10 > (defun foo () 42)
FOO

CL-USER 11 > (flet ((foo () 82))
               (print (foo))
               (print (funcall 'foo))
               (print (funcall #'foo)))

82   ; the local definition
42   ; the symbol references the global definition
82   ; (function foo) / #'foo  references the local definition
Run Code Online (Sandbox Code Playgroud)

(funcall 'foo) 从符号中查找函数.

(funcall #'foo)从词法环境中调用函数.如果没有,则使用全局定义.

#'foo是一种简写符号(function foo).

CL-USER 19 > '#'foo
(FUNCTION FOO)
Run Code Online (Sandbox Code Playgroud)


Ben*_*yde 7

与大多数语言不同,Common Lisp实际上没有解析器.它有一个被称为读者的词法分析器.阅读器使用单个字符并在表格中查找它们并调用那里找到的函数[1].在Lisp中,解析器在其他语言中扮演的角色由宏实现.

[1] http://www.lispworks.com/documentation/lw51/CLHS/Body/02_b.htm

例如,分号的读者会占用该行的其余部分,并将其作为注释丢弃.所以,例如,读者开放paren.调用递归读取列表元素的函数.因此,例如单引号递归读取单个表单然后将其包装在引号中.因此'(1 2 3)被读作(引用(1 2 3)).有一些这些关键的复杂令牌读取器.

[2] http://www.lispworks.com/documentation/lw51/CLHS/Body/02_d.htm

角色#\#提供了一个放置一系列额外读者行为的地方.哈希读者重复主读者的设计.它消耗另一个角色并在表格中查找并调用在那里找到的函数.这些中有很多[3].

[3] http://www.lispworks.com/documentation/lw51/CLHS/Body/02_dh.htm

因此,例如,我们有一个类似于读取向量的列表的读者,例如#(1 2 3).因此,例如,我们对单个字符,这样你可以输入一个分号,双引号,或周期作为一个读者#\;,#\"#\. 分别.

要回答您的具体问题:引用的哈希读取器,例如#'foo,类似于常规引用的哈希读取器.它读取以下标记并将其包装在函数中.#'foo读作(函数foo).

可以修改阅读器表格以自定义语言.表中的条目称为读取器宏.这个名称往往会使人们感到困惑,因为它们与defmacro定义的宏完全不同.它们共同提供了所谓的"成长"语言的能力[4].

[4] http://www.catonmat.net/blog/growing-a-language-by-guy-steele/