(defmacro random-choice (&rest exprs)
`(case (random ,(length exprs))
,@(let ((key -1))
(mapcar #'(lambda (expr)
`(,(incf key) ,expr))
exprs))))
Run Code Online (Sandbox Code Playgroud)
所以我macroexpand-1在这个函数上执行了,我一般都理解这个宏是如何工作的,但我对格雷厄姆如何嵌套反引号`以及他如何使用@来扩展案例感到非常困惑.
,@案例扩展到(random ,(length exprs))案例中?mapcar主要是为了让我们可以增加key,但是这个宏如何知道应用mapcar总共(random ,(length exprs))一次?,@拼接的隐式列表是如何形成的?注意我非常愚蠢所以请用最基本的术语解释.
编辑:
我现在明白的是,最内层反引号(,(incf key) ,expr)确保了此功能首先计算所以其大致相当于(list (incf key) expr),然后
,@(let ((i 0))
(mapcar #'(lambda (expr)
`(,(incf i) ,expr))
args))
Run Code Online (Sandbox Code Playgroud)
被评估为类似于列表的东西'((0 a_0) (1 a_1) ... (n a_n)),因为我们已经,@将它"拼接"成了
((0 a_0))
((1 a_n))
.
.
.
((n a_n))
Run Code Online (Sandbox Code Playgroud)
最后(case (random ,(length exprs))进行评估
case (random n),它也给了我们外括号,留给我们
(case (random n)
((0 a_0))
((1 a_n))
.
.
.
((n a_n)))
Run Code Online (Sandbox Code Playgroud)
我的事件序列是否正确?我在网上找不到任何资源来验证,格雷厄姆的书并没有像这样打破它.
写它的另一种方法(摆脱LET,MAPCAR +副作用INCF代码):
CL-USER 44 > (defmacro random-choice (&rest exprs &aux (n (length exprs)))
`(case (random ,n)
,@(loop for ci below n and expr in exprs
collect `(,ci ,expr))))
RANDOM-CHOICE
CL-USER 45 > (macroexpand-1 '(random-choice 10 21 32 43))
(CASE (RANDOM 4) (0 10) (1 21) (2 32) (3 43))
Run Code Online (Sandbox Code Playgroud)
宏使用带有计算的反引号形式.我们可以提取计算并将部分分配给变量:
CL-USER 46 > (defmacro random-choice (&rest exprs &aux (n (length exprs)))
(let ((keyform `(random ,n))
(clauses (loop for ci below n and expr in exprs
collect `(,ci ,expr))))
`(case ,keyform
,@clauses)))
RANDOM-CHOICE
CL-USER 47 > (macroexpand-1 '(random-choice 10 21 32 43))
(CASE (RANDOM 4) (0 10) (1 21) (2 32) (3 43))
Run Code Online (Sandbox Code Playgroud)
正如您所看到的那样,反引号形式可以独立计算,并在最后以反引号形式组装.
当宏函数包含代码片段时,最好将它们保留为带引号或反引号的形式 - >这使它们更容易在宏函数中识别.用列表计算替换它们(使用list,, cons......)不太方便且可读性差.但是,然后需要将反引号/不引号的顺序正确.在我的例子中,它稍微容易一些,因为部件是独立计算的.这有助于理解宏,因为它更符合以下语法case:
CASE keyform {normal-clause}* [otherwise-clause]
normal-clause::= (keys form*)
Run Code Online (Sandbox Code Playgroud)
这里我们只使用keyform和0..n-1子句{normal-clause}*.我们也不使用otherwise-clause.
| 归档时间: |
|
| 查看次数: |
107 次 |
| 最近记录: |