代码之家  ›  专栏  ›  技术社区  ›  Lone Learner

(清单1234)和(1234)之间的区别?

  •  0
  • Lone Learner  · 技术社区  · 6 年前

    这是我的代码:

    (format t "~a~%" (list 1 2 3 4))
    (format t "~a~%" '(1 2 3 4))
    (format t "~a~%" (remove-if-not #'evenp (list 1 2 3 4)))
    (format t "~a~%" (remove-if-not #'evenp '(1 2 3 4)))
    

    以下是输出:

    $ clisp bar.lisp 
    (1 2 3 4)
    (1 2 3 4)
    (2 4)
    (2 4)
    

    我的问题是:

    1. 这两种语法的区别是什么: (list 1 2 3 4) '(1 2 3 4)
    2. 使用一种语法比使用另一种语法有什么优势吗?
    2 回复  |  直到 6 年前
        1
  •  3
  •   Gwang-Jin Kim    6 年前

    两者的区别 '(1 2 3 4) (list 1 2 3 4) 结果似乎完全一样 (1 2 3 4) 是不可见的,因为Lisp中的数字会自行计算。

    (list (+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5))
    ;; returns/evaluates to:
    (3 5 7 9) ;; each of the arguments in a list gets evaluated.
    
    
    ;; while:
    '((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; equals to: (quote ((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)))
    ;; returns/evaluates to:
    ((+ 1 2) (+ 2 3) (+ 3 4) (+ 4 5)) ;; arguments of list not evaluated
    ;; since `quote` means: take the argument as data - unevaluated.
    

    现在你清楚地看到了区别: '(1 2 3 4) 扩展到(因此是语法糖到) (quote (1 2 3 4)) 是一个 特殊形式 虽然 (列表1 2 3 4) 是一个 作用 . Lisp中的函数计算每个参数 . 但特殊形式并不能评估他们的每一个论点。 quote 的论点 引用 未进行评估。

    现在你看,有了 a , b , c , d 之前没有定义,这个

    '(a b c d) 
    ;; returns: (A B C D)
    

    工作,因为b c d没有被评估!

    但是:

    (list a b c d)
    

    导致错误:

    *** - SYSTEM::READ-EVAL-PRINT: variable A has no value
    The following restarts are available:
    USE-VALUE      :R1      Input a value to be used instead of A.
    STORE-VALUE    :R2      Input a new value for A.
    ABORT          :R3      Abort main loop
    

    因为两者都不是 A. 也没有 B 也没有 C 也没有 D 但Lisp解释器会尝试对它们进行求值,因为它们是函数参数。

    但你仍然可以 (A B C D) 使用函数 list 通过引用每个参数——从而使它们计算为符号名,而不是Lisp解释器来查找其未定义的值:

    (list 'a 'b 'c 'd)
    ;; now it works - though a b c d are not defined yet:
    (A B C D)
    

    注意:有趣的是,并非在所有语言中,函数参数都会被计算,因为它们是函数参数。而Python对其所有函数参数的求值类似于Lisp 之前 进入和评估功能体,R不需要。

    因此,函数参数的求值是处理函数参数的一种特定于Lisp的方法。(但它与大多数其他语言一样——我只想说,函数参数的求值不是一般规则)。这也是Lisp宏(和特殊形式)与Lisp函数之间的根本区别。在Lisp宏(和特殊形式)中,可以指定哪些函数参数在宏体中得到计算,哪些不得到计算。这样您就可以完全控制任何宏参数的计算。在Lisp函数中,默认情况下,所有参数在进入函数体之前都会先求值。

    这也是为什么您还必须学习Lisp中的宏(指定特殊形式)的原因之一。 引用 连同 列表 实际上是所有宏的母亲。任何 backquote unquote 操作可以表示为 引用 列表 (尽管对于人类读者来说,这看起来更令人厌恶)。你可以想象,关于这个话题,人们可以思考很长时间。你的问题直接涉及到Lisp如此迷人的核心和本质。

        2
  •  1
  •   Svante    6 年前

    区别在于创建列表的时间。一个是由 读者 ,另一个在 运行时 .

    读者负责将文本文件转换为表示代码的数据结构。这种数据结构碰巧主要是列表;这就是Lisp(列表处理)的思想。

    当读者阅读 文本 (foo bar) ,它创建了两个元素的列表,即符号 foo bar 。然后将其编译,即转换为一个函数调用(或其他调用,但不在此转移),其中 使用名为的变量的值调用 酒吧 .

    有一个特殊的操作符告诉编译器 要进行此翻译: quote .当编译器遇到 列表 (由读者构造) (quote (foo bar)) ,它使用“受保护”的东西 引用 字面上 ,也就是说,正是这个列表 (富吧) 由读者构建。

    撇号 ' 是一个缩写 引用 所以 '(foo bar) 被解读为 (引用(foo-bar)) .

    表格 '(1 2 3) 因此,这正是您写入文本文件的列表,正如读者所读的那样。这叫做 文字列表 .

    另一方面 (list 1 2 3) 是函数的正常函数调用 list 有三个论点。在运行时执行此代码时,它会创建这些参数的新列表。

    只有当文本列表是常量时,才应该使用它。例如,当创建多维数组时,您可能知道它的大小总是相同的(可能这是问题的内在原因),所以您可以编写 (make-array '(3 5)) .如果要使其可配置,请将其参数化: (make-array (list width height)) .

    您必须避免的一件事是修改文字数据。