我正在读的一本书[1]是这样说的:
\n\n\n编程语言中最有趣的发展之一是可扩展语言的创建,其语法和语义可以在程序内更改。最早和\n最常提出的语言扩展方案之一是宏定义。
\n
您能否给出一个扩展 Lisp 编程语言的语法和语义的 Lisp 宏示例(并附上解释)?
\n[1]解析、翻译和编译理论,第 1 卷解析:Aho 和 Ullman,第 58 页。
\n想象一下当时的场景:1958 年,FORTRAN 刚刚被发明。仅在原子测试的余辉的照耀下,原始 Lisp 程序员正在以原始 FORTRAN 程序员一贯的方式用原始 Lisp 编写循环:
(prog ((i 0)) ;i is 0
start ;label beginning of loop
(if (>= i 10)
(go end)) ;skip to end when finished
(do-hard-sums-on i) ;hard sums!
(setf i (+ i 1)) ;increment i
(go start) ;jump to start
end) ;end
Run Code Online (Sandbox Code Playgroud)
(当然,这一切都是大写的,因为当时还没有发明小写字母,而且我写的东西setf会更难看,因为setf(宏!)当时也还没有发明)。
另一位从未来逃到 1958 年的 Lisp 程序员,从喷气背包中冒出微毒的烟雾。“看,”他们说,“我们可以写出这个奇怪的未来事物”:
(defmacro sloop ((var init limit &optional (step 1)) &body forms)
(let ((<start> (make-symbol "START")) ;avoid hygiene problems ...
(<end> (make-symbol "END"))
(<limit> (make-symbol "LIMIT")) ;... and multiple evaluation problems
(<step> (make-symbol "STEP")))
`(prog ((,var ,init)
(,<limit> ,limit)
(,<step> ,step))
,<start>
(if (>= ,var ,<limit>)
(go ,<end>))
,@forms
(setf ,var (+ ,var ,<step>))
(go ,<start>)
,<end>)))
Run Code Online (Sandbox Code Playgroud)
他们说,“现在你可以写这个”:
(sloop (i 0 10)
(do-hard-sums i))
Run Code Online (Sandbox Code Playgroud)
简单的循环就这样被发明了。
稍后回到这里,我们可以看到这个循环扩展成什么:
(sloop (i 0 10)
(format t "~&i = ~D~%" i))
->
(prog ((i 0) (#:limit 10) (#:step 1))
#:start (if (>= i #:limit) (go #:end))
(format t "~&i = ~D~%" i)
(setf i (+ i #:step))
(go #:start)
#:end)
Run Code Online (Sandbox Code Playgroud)
这是原始 Lisp 程序员用来手动输入的代码。我们可以运行这个:
> (sloop (i 0 10)
(format t "~&i = ~D~%" i))
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
i = 6
i = 7
i = 8
i = 9
nil
Run Code Online (Sandbox Code Playgroud)
事实上,这就是当今 Lisp 中循环的工作方式。如果我尝试一个简单的do循环(Common Lisp 的预定义宏之一),我们可以看到它扩展成什么:
(do ((i 0 (+ i 1)))
((>= i 10))
(format t "~&i = ~D~%" i))
->
(block nil
(let ((i 0))
(declare (ignorable i))
(declare)
(tagbody
#:g1481 (if (>= i 10) (go #:g1480))
(tagbody (format t "~&i = ~D~%" i)
(setq i (+ i 1)))
(go #:g1481)
#:g1480)))
Run Code Online (Sandbox Code Playgroud)
嗯,这个扩展是不一样的,它使用了我没有讨论过的结构,但是你可以看到重要的事情:这个循环已经被重写为使用GO. 而且,尽管 Common Lisp 没有定义其循环宏的扩展,但几乎可以肯定的是,所有标准宏都扩展成这样的东西(但通常更复杂)。
换句话说:Lisp 没有任何原始循环结构,但所有此类结构都是通过宏添加到语言中的。这些宏以及以其他方式扩展语言的其他宏可以由用户编写:它们不必由语言本身提供。
Lisp 是一种可编程编程语言。
| 归档时间: |
|
| 查看次数: |
194 次 |
| 最近记录: |