是什么使Lisp宏如此特别? [英] What makes Lisp macros so special?

查看:95
本文介绍了是什么使Lisp宏如此特别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

阅读关于编程语言的Paul Graham的论文,人们会认为

Reading Paul Graham's essays on programming languages one would think that Lisp macros are the only way to go. As a busy developer, working on other platforms, I have not had the privilege of using Lisp macros. As someone who wants to understand the buzz, please explain what makes this feature so powerful.

也请将此与我从Python,Java,C#或C开发的世界中了解的东西联系起来.

Please also relate this to something I would understand from the worlds of Python, Java, C# or C development.

推荐答案

要给出简短的答案,宏用于定义Common Lisp或领域特定语言(DSL)的语言语法扩展.这些语言直接嵌入到现有的Lisp代码中.现在,DSL可以具有类似于Lisp的语法(例如,针对Common Lisp的Peter Norvig的 Prolog解释器)或完全不同(例如,Clojure的 Infix Notation Math ).

To give the short answer, macros are used for defining language syntax extensions to Common Lisp or Domain Specific Languages (DSLs). These languages are embedded right into the existing Lisp code. Now, the DSLs can have syntax similar to Lisp (like Peter Norvig's Prolog Interpreter for Common Lisp) or completely different (e.g. Infix Notation Math for Clojure).

这是一个更具体的示例:
Python在语言中内置了列表理解功能.这为常见情况提供了简单的语法.线

Here is a more concrete example:
Python has list comprehensions built into the language. This gives a simple syntax for a common case. The line

divisibleByTwo = [x for x in range(10) if x % 2 == 0]

产生一个包含0到9之间所有偶数的列表.回到 Python 1.5 没有这样的语法;您将使用更多类似这样的内容:

yields a list containing all even numbers between 0 and 9. Back in the Python 1.5 days there was no such syntax; you'd use something more like this:

divisibleByTwo = []
for x in range( 10 ):
   if x % 2 == 0:
      divisibleByTwo.append( x )

这些在功能上都是等效的.让我们调用我们的怀疑暂停,并假设Lisp具有非常有限的循环宏,该宏仅进行迭代并且没有简单的方法来执行等效于列表推导的操作.

These are both functionally equivalent. Let's invoke our suspension of disbelief and pretend Lisp has a very limited loop macro that just does iteration and no easy way to do the equivalent of list comprehensions.

在Lisp中,您可以编写以下内容.我应该注意,这个人为设计的示例与Python代码相同,而不是Lisp代码的良好示例.

In Lisp you could write the following. I should note this contrived example is picked to be identical to the Python code not a good example of Lisp code.

;; the following two functions just make equivalent of Python's range function
;; you can safely ignore them unless you are running this code
(defun range-helper (x)
  (if (= x 0)
      (list x)
      (cons x (range-helper (- x 1)))))

(defun range (x)
  (reverse (range-helper (- x 1))))

;; equivalent to the python example:
;; define a variable
(defvar divisibleByTwo nil)

;; loop from 0 upto and including 9
(loop for x in (range 10)
   ;; test for divisibility by two
   if (= (mod x 2) 0) 
   ;; append to the list
   do (setq divisibleByTwo (append divisibleByTwo (list x))))

在继续之前,我应该更好地解释什么是宏.这是对 by 代码执行的转换.也就是说,由解释器(或编译器)读取的一段代码将代码作为参数,进行处理并返回结果,然后就地运行该结果.

Before I go further, I should better explain what a macro is. It is a transformation performed on code by code. That is, a piece of code, read by the interpreter (or compiler), which takes in code as an argument, manipulates and the returns the result, which is then run in-place.

当然,很多打字工作和程序员都是懒惰的.因此,我们可以定义DSL来进行列表理解.实际上,我们已经在使用一个宏(循环宏).

Of course that's a lot of typing and programmers are lazy. So we could define DSL for doing list comprehensions. In fact, we're using one macro already (the loop macro).

Lisp定义了几种特殊的语法形式.引号(')表示下一个标记是文字.准引号或反引号(`)表示下一个标记是带有转义符的文字.转义由逗号运算符指示.文字'(1 2 3)等同于Python的[1, 2, 3].您可以将其分配给另一个变量或就地使用它.您可以将`(1 2 ,x)视为Python的[1, 2, x]的等效项,其中x是先前定义的变量.此列表表示法是宏的不可思议的一部分.第二部分是Lisp阅读器,它可以智能地将宏替换为代码,但是最好在下面进行说明:

Lisp defines a couple of special syntax forms. The quote (') indicates the next token is a literal. The quasiquote or backtick (`) indicates the next token is a literal with escapes. Escapes are indicated by the comma operator. The literal '(1 2 3) is the equivalent of Python's [1, 2, 3]. You can assign it to another variable or use it in place. You can think of `(1 2 ,x) as the equivalent of Python's [1, 2, x] where x is a variable previously defined. This list notation is part of the magic that goes into macros. The second part is the Lisp reader which intelligently substitutes macros for code but that is best illustrated below:

因此,我们可以定义一个名为lcomp的宏(列表理解的缩写).它的语法与我们在示例[x for x in range(10) if x % 2 == 0]-(lcomp x for x in (range 10) if (= (% x 2) 0))

So we can define a macro called lcomp (short for list comprehension). It's syntax will be exactly like the python that we used in the example [x for x in range(10) if x % 2 == 0] - (lcomp x for x in (range 10) if (= (% x 2) 0))

(defmacro lcomp (expression for var in list conditional conditional-test)
  ;; create a unique variable name for the result
  (let ((result (gensym)))
    ;; the arguments are really code so we can substitute them 
    ;; store nil in the unique variable name generated above
    `(let ((,result nil))
       ;; var is a variable name
       ;; list is the list literal we are suppose to iterate over
       (loop for ,var in ,list
            ;; conditional is if or unless
            ;; conditional-test is (= (mod x 2) 0) in our examples
            ,conditional ,conditional-test
            ;; and this is the action from the earlier lisp example
            ;; result = result + [x] in python
            do (setq ,result (append ,result (list ,expression))))
           ;; return the result 
       ,result)))

现在我们可以在命令行执行:

Now we can execute at the command line:

CL-USER> (lcomp x for x in (range 10) if (= (mod x 2) 0))
(0 2 4 6 8)

很整洁,是吗?现在它不止于此.如果需要,您可以使用一种机制或一支画笔.您可以具有任何可能需要的语法.像Python或C#的with语法.或.NET的LINQ语法.最后,这就是吸引人们使用Lisp的原因-最终的灵活性.

Pretty neat, huh? Now it doesn't stop there. You have a mechanism, or a paintbrush, if you like. You can have any syntax you could possibly want. Like Python or C#'s with syntax. Or .NET's LINQ syntax. In end, this is what attracts people to Lisp - ultimate flexibility.

这篇关于是什么使Lisp宏如此特别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆