【发布时间】:2012-05-27 01:54:06
【问题描述】:
我是 Lisp 新手。我遇到了 2 个术语“列表”和“S 表达式”。我只是无法区分它们。它们只是 Lisp 中的同义词吗?
【问题讨论】:
-
欲了解更多信息,请参阅C2 wiki on sexprs。
标签: list lisp s-expression
我是 Lisp 新手。我遇到了 2 个术语“列表”和“S 表达式”。我只是无法区分它们。它们只是 Lisp 中的同义词吗?
【问题讨论】:
标签: list lisp s-expression
首先,不是所有的 S 表达式都代表列表; foobar 等表示裸原子的表达式也被视为 S 表达式。正如“cons cell”语法(car . cons),当“cons”部分本身不是另一个列表(或nil)时使用。更熟悉的列表表达式,例如 (a b c d),只是嵌套 cons 单元链的语法糖;该示例扩展为(a . (b . (c . (d . nil))))。
其次,术语“S 表达式”指的是语法 - (items like this (possibly nested))。这样的 S 表达式是列表的 Lisp 源代码中的表示,但从技术上讲,它本身并不是列表。这种区别与十进制数字序列与其数值之间的区别,或者引号内的字符序列与结果字符串之间的区别相同。
这可能是一个过于技术性的区别;程序员经常引用值的文字表示,就好像它们就是值本身一样。但是对于 Lisp 和列表,事情会变得有点棘手,因为 Lisp 程序中的一切在技术上都是一个列表。
例如,考虑这个表达式:
(+ 1 2)
上面是一个简单的 S 表达式,它表示一个平面列表,由原子 +、1 和 2 组成。
但是,在 Lisp 程序中,这样的列表将被解释为以 1 和 2 作为参数调用 + 函数。 (请注意,这样解释的是 list,而不是 S 表达式;评估者收到的列表是由读者预先解析的,而不是源代码文本。)
因此,虽然上面的 S 表达式表示一个列表,但在 Lisp 程序的上下文中,它很少被称为为“列表”。除非讨论宏,或者读者的内部工作,或者因为其他代码生成或解析上下文而进行元句法讨论,否则典型的 Lisp 程序员会将上述内容视为数字表达式。
另一方面,以下任何 S 表达式都可能 被称为“列表”,因为将它们评估为 Lisp 代码会生成由上述文字 S 表达式表示的列表作为运行时值:
'(+ 1 2)
(quote (+ 1 2))
(list '+ 1 2)
当然,代码和数据的等价性是 Lisp 的一大优点,所以区别是流动的。但我的观点是,虽然以上所有内容都是 S 表达式和列表,但在随意的 Lisp 语言中,只有一些会被称为“列表”。
【讨论】:
eval.
S 表达式是数据的表示法。
历史上一个s-expression(symbolic expression的缩写)被描述为:
FOO 和 BAR
( expression-1 . expression-2 )
NIL
(A.(B.NIL))写成更简单的列表@9876
另请注意,历史上程序文本的编写方式不同。函数ASSOC 的示例。
assoc[x;y] =
eq[caar[y];x] -> cadar[y];
T -> assoc[x;cdr[y]]
历史上还存在从这些 m 表达式(元表达式的缩写)到 s 表达式的映射。如今,大多数 Lisp 程序代码都是使用 s 表达式编写的。
这里有描述:McCarthy, Recursive Functions of Symbolic Expressions
在如今的像 Common Lisp 这样的 Lisp 编程语言中,s-expressions 有更多的语法并且可以编码更多的数据类型:
symbol123、|This is a symbol with spaces|
123、1.0、1/3、..."This is a string"
#\a、#\space
#(a b c)
( a . b ), (a b c)
; this is a comment,#| this is a comment |#
还有更多。
列表
列表是一个数据结构。它由 cons 单元格和列表结束标记组成。在 Lisp 中,列表具有 notation 作为 s 表达式中的列表。您可以对列表使用其他一些表示法,但在 Lisp 中,人们已经决定使用 s-expression 语法来编写它们。
旁注:程序和表格
在像 Common Lisp 这样的编程语言中,编程语言的表达式不是文本,而是数据!这与许多其他编程语言不同。编程语言 Common Lisp 中的表达式称为Lisp forms。
例如,函数调用是 Lisp 数据,其中调用是一个列表,其中函数符号作为它的第一个元素,接下来的元素是它的参数。
我们可以写成(sin 3.0)。但它确实是数据。我们也可以构建数据。
评估 Lisp 表单的函数称为 EVAL,它采用 Lisp 数据,而不是程序文本或程序文本字符串。因此,您可以使用返回 Lisp 数据的 Lisp 函数构建程序:(EVAL (LIST 'SIN 3.0)) 的计算结果为 0.14112。
由于 Lisp 表单具有数据表示,它们通常使用 Lisp 的外部数据表示来编写 - 这是什么? - s 表达式!
它是 s 表达式。 Lisp 表单作为 Lisp 数据被外部写入为 s 表达式。
【讨论】:
您应该首先了解 Lisp 的主要功能 - 程序可以作为数据进行操作。与其他语言(如 C 或 Java)不同,您使用特殊语法({、}、class、define 等)编写程序,在 Lisp 中,您将代码编写为(嵌套)列表(顺便说一句,这允许直接表达abstract syntactic trees)。再说一遍:你编写的程序看起来就像语言的数据结构。
当你把它当作数据来谈时,你称它为“列表”,但当你谈程序代码时,你应该更好使用术语“s-expression”。因此,从技术上讲,它们是相似的,但在不同的上下文中使用。混合这些术语的唯一真正地方是元编程(通常使用宏)。
还要注意,s 表达式也可能由唯一的 原子 组成(如数字、字符串等)。
【讨论】:
eval 函数不对字符串进行操作;在这一点上,它与大多数现代动态语言中的同名函数不同。相反,它希望它的参数已经是代码的内存表示,即(分层嵌套的树)列表。 reader 将 S 表达式转换为要评估的列表。所以,S-表达式:列表的文本表示。序列化,实际上,与 JSON 或 XML 表示对象树的方式非常相似。
S 表达式的简单定义是
(define S-expression?
(λ (object)
(or (atom? object) (list? object))))
;; Where atom? is:
(define atom?
(λ (object)
(and (not (pair? object)) (not (null? object)))))
;; And list? is:
(define list? (λ (object)
(let loop ((l1 object) (l2 object))
(if (pair? l1)
(let ((l1 (cdr l1)))
(cond ((eq? l1 l2) #f)
((pair? l1) (loop (cdr l1) (cdr l2)))
(else (null? l1))))
(null? l1)))))
【讨论】:
两者的写法相似:(blah blah blah),可能是嵌套的。有一个区别 - 列表以撇号为前缀。
关于评估:
如果需要,我们可以将列表转换为 s-exp,反之亦然。
国际会计准则:
【讨论】:
s-expression 保留用于以元文本方式专门讨论语法。