当前位置:  开发笔记 > 编程语言 > 正文

什么时候在Lisp中使用'(或引用)?

如何解决《什么时候在Lisp中使用'(或引用)?》经验,为你挑选了5个好方法。

在通过介绍性的Lisp书的主要部分之后,我仍然无法理解特殊运算符(quote)(或等效的')函数的作用,但这已经是我见过的所有Lisp代码.

它有什么作用?



1> Mikael Janss..:

简短的回答 绕过默认的评价规则,也没有计算表达式(符号或S-EXP),正好将它传递给函数的类型.

长答案:默认评估规则

当调用常规(我将在稍后讨论)函数时,将评估传递给它的所有参数.这意味着你可以这样写:

(* (+ a 2)
   3)

然后(+ a 2)通过评估来评估,然后在当前变量绑定集中查找a符号的值a,然后替换.Say 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 #:
  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 #)
0] 

因为spiffy-symbol在目前的范围内没有!

加起来

quote,backquote(用逗号),并且list是用于创建列表的一些工具,它们不仅是值列表,而且如您所见,可以用作轻量级(无需定义struct)数据结构!

如果你想了解更多,我推荐Peter Seibel的书" Practical Common Lisp "来学习Lisp的实用方法,如果你已经完成了编程.最终在你的Lisp之旅中,你也将开始使用包.Ron Garret的The Idiot's Common Lisp软件包指南将为您提供很好的解释.

快乐的黑客!



2> Adam Rosenfi..:

它说"不评价我".例如,如果您想将列表用作数据而不是代码,则可以在其前面加上引号.例如,

(print '(+ 3 4))打印"(+ 3 4)",而 (print (+ 3 4))打印"7"



3> Xanthir..:

其他人对这个问题的回答令人钦佩,Matthias Benkard提出了一个很好的警告.

不要使用引用来创建您将进行修改的列表.规范允许编译器将引用列表视为常量.通常,编译器将通过在内存中为它们创建单个值来优化常量,然后从出现常量的所有位置引用该单个值.换句话说,它可以将常量视为匿名全局变量.

这可能会导致明显的问题.如果修改常量,它可以很好地修改完全不相关代码中相同常量的其他用法.例如,您可以将某个变量与某个函数中的"(1 1)"进行比较,并在完全不同的函数中,使用"(1 1)"启动列表,然后向其中添加更多内容.在运行这些函数时,您可能会发现第一个函数不再正确匹配,因为它现在正在尝试将变量与'(1 1 2 3 5 8 13)进行比较,这是第二个函数返回的内容.这两个函数完全不相关,但由于使用了常量,它们相互影响.甚至可能发生更疯狂的不良影响,就像完全正常的列表迭代突然无限循环一样.

需要常量列表时使用引号,例如用于比较.在修改结果时使用列表.



4> Matthias Ben..:

这个问题的一个答案是QUOTE"创建列表数据结构".这不太对.QUOTE比这更基础.事实上,QUOTE是一个微不足道的运算符:它的目的是防止任何事情发生.特别是,它不会创造任何东西.

什么(QUOTE X)说的基本上是"什么都不做,只给我X."X不必是(QUOTE(ABC))中的列表或(QUOTE FOO)中的符号.它可以是任何物体.实际上,评估由(LIST'QUOTE SOME-OBJECT)生成的列表的结果将始终只返回SOME-OBJECT,无论它是什么.

现在,(QUOTE(ABC))似乎创建了一个元素为A,B和C的列表的原因是这样的列表确实是它返回的内容; 但是在评估QUOTE表单时,列表通常已经存在了一段时间(作为QUOTE表单的一个组件!),在执行代码之前由加载器或读取器创建.

这种情况的一个含义往往是经常惹恼新手,因为修改QUOTE表单返回的列表是非常不明智的.对于所有意图和目的,QUOTE返回的数据被视为正在执行的代码的一部分,因此应被视为只读!



5> Kyle Burton..:

引用可防止执行或评估表单,而是将其转换为数据.通常,您可以通过评估数据来执行数据.

quote创建列表数据结构,例如,以下是等效的:

(quote a)
'a

它还可以用于创建列表(或树):

(quote (1 2 3))
'(1 2 3)

你可能最好得到关于lisp的入门书,例如Practical Common Lisp(可在线阅读).

推荐阅读
喜生-Da
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有