什么时候在Lisp中使用'(或引用)? [英] When to use ' (or quote) in Lisp?

查看:82
本文介绍了什么时候在Lisp中使用'(或引用)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在介绍Lisp入门书籍的主要部分之后,我仍然不明白特殊运算符(quote)(或等效的')函数的作用,但是这遍历了Lisp代码,已经看到.

它是做什么的?

解决方案

简短回答 绕过默认的求值规则,并且不求值表达式(符号或s-exp),并将其传递给与输入类型完全相同的函数.

详细答案:默认评估规则

当调用常规(稍后再介绍)函数时,将评估传递给该函数的所有参数.这意味着您可以编写以下代码:

(* (+ a 2)
   3)

依次通过评估a和2来评估(+ a 2).在当前变量绑定集中查找符号a的值,然后将其替换.假设a当前绑定到值3:

(let ((a 3))
  (* (+ a 2)
     3))

我们得到(+ 3 2),然后在3和2上调用+产生5.我们的原始形式现在是(* 5 3)产生15.

已经解释了quote

好的.如上所示,对函数的所有参数都进行了评估,因此,如果您要传递符号 a而不是其值,则不要评估它. Lisp符号既可以作为其值的两倍,也可以作为使用其他语言的标记的字符串,例如哈希表的键.

这是quote的来源.假设您要从Python应用程序中绘制资源分配,而是在Lisp中进行绘制.让您的Python应用执行以下操作:

 print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")
 

提供如下所示的输出(略微精确):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

还记得我说的关于quote(勾号")的原因,该默认规则不适用吗?好的.否则将发生的情况是查找allocatefree的值,而我们不希望这样.我们希望在Lisp中执行以下操作:

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

对于上面给出的数据,将执行以下函数调用序列:

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

但是list呢?

好吧,有时候您要做要评估参数.假设您有一个漂亮的函数来处理数字和字符串并返回结果列表.让我们做一个错误的开始:

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

嘿!那不是我们想要的.我们想选择性地评估一些参数,而将其他参数保留为符号.尝试#2!

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

不仅是quote,而且是backquote

好多了!顺便说一句,这种模式在(大多数)宏中非常常见,以至于有专门的语法可以做到这一点.反引号:

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

就像使用quote一样,但是具有通过在参数前面加上逗号来显式评估某些参数的选项.结果等同于使用list,但是如果要从宏生成代码,则通常只需要评估返回的代码的一小部分,因此反引号更适合.对于较短的列表,list可能更具可读性.

嘿,您忘记了quote

那么,这把我们留在哪里呢?哦,对,quote实际上是做什么的?它只是返回未计算的参数!还记得我一开始说的关于常规函数的内容吗?事实证明,某些运算符/函数需要评估其参数.如IF-如果不采用else分支,您将不希望对它进行评估,对吗?所谓的特殊运算符与宏一起工作.特殊运算符也是该语言的公理"-最少的规则集-您可以通过以不同方式将它们组合在一起来实现Lisp的其余部分.

返回quote,但是:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

与(在Steel-Bank Common Lisp上)比较:

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING   {A69F6A9}>:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0] 

因为当前范围中没有spiffy-symbol

总结

quotebackquote(带逗号)和list是用于创建列表的一些工具,这些工具不仅是值列表,而且如您所见可以用作轻量级对象(不需要定义struct)数据结构!

如果您想了解更多信息,我建议彼得·塞贝尔(Peter Seibel)的书实用的普通Lisp 作为学习Lisp的实用方法,如果您已经开始进行编程.最终,在您的Lisp旅程中,您也将开始使用软件包.罗恩·加勒特(Ron Garret)的《愚蠢的常见Lisp软件包指南》 将为您提供很好的解释.

黑客很开心!

After making it through the major parts of an introductory Lisp book, I still couldn't understand what the special operator (quote) (or equivalent ') function does, yet this has been all over Lisp code that I've seen.

What does it do?

解决方案

Short answer Bypass the default evaluation rules and do not evaluate the expression (symbol or s-exp), passing it along to the function exactly as typed.

Long Answer: The Default Evaluation Rule

When a regular (I'll come to that later) function is invoked, all arguments passed to it are evaluated. This means you can write this:

(* (+ a 2)
   3)

Which in turn evaluates (+ a 2), by evaluating a and 2. The value of the symbol a is looked up in the current variable binding set, and then replaced. Say a is currently bound to the value 3:

(let ((a 3))
  (* (+ a 2)
     3))

We'd get (+ 3 2), + is then invoked on 3 and 2 yielding 5. Our original form is now (* 5 3) yielding 15.

Explain quote Already!

Alright. As seen above, all arguments to a function are evaluated, so if you would like to pass the symbol a and not its value, you don't want to evaluate it. Lisp symbols can double both as their values, and markers where you in other languages would have used strings, such as keys to hash tables.

This is where quote comes in. Say you want to plot resource allocations from a Python application, but rather do the plotting in Lisp. Have your Python app do something like this:

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

Giving you output looking like this (slightly prettyfied):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

Remember what I said about quote ("tick") causing the default rule not to apply? Good. What would otherwise happen is that the values of allocate and free are looked up, and we don't want that. In our Lisp, we wish to do:

(dolist (entry allocation-log)
  (case (first entry)
    (allocate (plot-allocation (second entry)))
    (free (plot-free (second entry)))))

For the data given above, the following sequence of function calls would have been made:

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

But What About list?

Well, sometimes you do want to evaluate the arguments. Say you have a nifty function manipulating a number and a string and returning a list of the resulting ... things. Let's make a false start:

(defun mess-with (number string)
  '(value-of-number (1+ number) something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))

Hey! That's not what we wanted. We want to selectively evaluate some arguments, and leave the others as symbols. Try #2!

(defun mess-with (number string)
  (list 'value-of-number (1+ number) 'something-with-string (length string)))

Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)

Not Just quote, But backquote

Much better! Incidently, this pattern is so common in (mostly) macros, that there is special syntax for doing just that. The backquote:

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

It's like using quote, but with the option to explicitly evaluate some arguments by prefixing them with comma. The result is equivalent to using list, but if you're generating code from a macro you often only want to evaluate small parts of the code returned, so the backquote is more suited. For shorter lists, list can be more readable.

Hey, You Forgot About quote!

So, where does this leave us? Oh right, what does quote actually do? It simply returns its argument(s) unevaluated! Remember what I said in the beginning about regular functions? Turns out that some operators/functions need to not evaluate their arguments. Such as IF -- you wouldn't want the else branch to be evaluated if it wasn't taken, right? So-called special operators, together with macros, work like that. Special operators are also the "axiom" of the language -- minimal set of rules -- upon which you can implement the rest of Lisp by combining them together in different ways.

Back to quote, though:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

Compare to (on Steel-Bank Common Lisp):

Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING   {A69F6A9}>:
  The variable SPIFFY-SYMBOL is unbound.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0] 

Because there is no spiffy-symbol in the current scope!

Summing Up

quote, backquote (with comma), and list are some of the tools you use to create lists, that are not only lists of values, but as you seen can be used as lightweight (no need to define a struct) data structures!

If you wish to learn more, I recommend Peter Seibel's book Practical Common Lisp for a practical approach to learning Lisp, if you're already into programming at large. Eventually on your Lisp journey, you'll start using packages too. Ron Garret's The Idiot's Guide to Common Lisp Packages will give you good explanation of those.

Happy hacking!

这篇关于什么时候在Lisp中使用'(或引用)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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