我很困惑 S-Expression 不是什么?
在scheme/racket中,任何带有define的东西都不是S表达式:
(define a 2)
(define (my-print x)
(println x))
Run Code Online (Sandbox Code Playgroud)
或者也许这只是不评估“价值”的事情?喜欢导入和评论吗?:
#lang racket/base
; and comments?
Run Code Online (Sandbox Code Playgroud)
我不确定我是否真的理解哪些东西不符合 s 表达式?
只是想更好地理解 S 表达式。
我怀疑你可能指的是“表达式”而不是“s-表达式”,因为后一个术语在Scheme中根本不存在。然而。
\n在传统意义上,s 表达式是:
\n(<car> . <cdr>)或者写为where<car>和<cdr>are s 表达式的cons 。显然,这在很大程度上取决于“原子”的定义。原子通常是任何不是缺点的东西,它们至少包括:
\n();foo等foo-bar;请注意,此定义没有引用值:s 表达式只是结构族的定义。
\n然后,传统的 Lisp 将通过编写阅读器来定义,该阅读器将 s 表达式的书面表示转换为 s 表达式。这位读者会定义什么是原子,并且几乎总是会包含一些方便的语法简写:例如(a . (b . (c . ())))有一个简写。(a b c)因此,读者为您提供 s-表达式,然后您编写一个求值器,它将评估可能的 s-表达式的一小部分作为程序(请注意,有大量的 s-表达式不是合法的程序)。最后还有一台打印机,可以将 s 表达式转回书面形式。
因此,传统的 Lisp 是通过将语义(通过求值器)分配给 s 表达式的某个子集来定义的。Lisp 程序只是一个被求值的 s 表达式序列, Lisp 程序中的所有内容都是 s 表达式。
\n“表达式”的定义似乎根据 Lisp 的不同而有所不同:特别是 Common Lisp 规范定义“表达式”的方式与我即将给出的定义不同(注意我\'我已经成为 CL 程序员很长时间了,我并不反对这里的规范)。
\n我认为定义这个术语的最有用的方法是借用数学家使用的通常定义,毕竟他们已经做了很长时间的事情:表达式是具有值的东西,或者表达式是一个公式可以出现在作业的右侧。因此,如果您可以写“x = ...”,那么“...”就是一个表达式。
\n这直接适用于编程语言:如果您可以在Scheme中编写,(set! x ...)则or (define x ...)then...是一个表达式:如果您不能,则它不是。请注意,这也适用于其他语言:如果您可以在 C 中编写“x = ...;”,则...是一个表达式。例如,你不能x = if (y == 1) 3; else 2;用 C 语言编写,因为if语句是语句,而不是表达式:你必须编写x = (y == 1)? 3 : 2;.
(请注意,“表达式”的概念根本不处理多个值:请参阅末尾的注释。)
\n这是我将在下面使用的表达式的定义。
\n传统的 Lisp 是表达式语言:这意味着该语言为其分配语义的任何 s-表达式(这又是 s-表达式的一个很小的子集)都是具有值 的表达式,尽管该值可能是未定义的。特别是,它意味着语言中不存在没有值的事物:不存在语句或其他神奇的事物:如果语言将语义分配给 s-表达式,那么它就是一个表达式。这是 Common Lisp 中的一个奇怪的例子:一个 s-表达式 like(defun name arglist ...)定义了一个函数,因此是该语言为其分配语义的 s-表达式之一。例如,你可以这样做
(let ((x (defun foo (y) y)))\n (cons x x))\nRun Code Online (Sandbox Code Playgroud)\n而这个表达式的值(foo . foo)实际上就是。在 CL 程序中看到defun除顶层之外的表单是一种严重的代码味道,但它是合法的 CL,因为一切都是 CL 中的表达式。
请注意,语言为其分配语义并因此对应于表达式的 s-表达式通常(几乎总是)结构化的事物,并且仅仅因为 s-表达式作为一个整体对应于一个表达式并不意味着它的所有部分都对应于一个表达式。 。例如
\n(cond\n (<test> <expression> ...)\n ...)\nRun Code Online (Sandbox Code Playgroud)\n是一个有效的表达式,但一般来说 s 表达式(<test> <expression> ...)不是:它们仅作为cond表单的一部分有效。然而<test>,所有的<expresssion>s都是有效的表达式。
然而,Scheme 的定义方式与传统 Lisp 不同:例如,R7RS (PDF 链接)中根本没有提及 s 表达式。最接近的可能是<datum>(第7.1.2节),它定义了read可以解析的内容:我认为可以肯定地说a<datum>是Scheme中的s-表达式。但Scheme并不是根据<datum>s来定义的:它是直接根据语言的书面语法来定义的。
Scheme 并不像传统的 Lisp 那样是一种表达语言。它定义了表达式,它称之为<expression>s,这些在 R7RS 的 7.1.3 中定义。与 Lisp 一样,s 的某些部分<expression>并不是它们本身<expression>s:Scheme 不会将它们视为仅仅是 s 表达式,但您可以这样认为它们(这是否有用)没有把握)。
然而,Scheme 中有很多东西不是表达式。例如,构成<program>(7.1.6) 的东西不是表达式,这意味着,例如(define ...)不是表达式:你不能说:
(let ((x (define y 1))) x)\nRun Code Online (Sandbox Code Playgroud)\n在方案中。你可以说
\n(let ((x (\xce\xbb ()\n (define y 1)\n y)))\n x)\nRun Code Online (Sandbox Code Playgroud)\n但这是因为(\xce\xbb () (define y 1) y) 是一个有效的表达式,尽管就像 Lisp 一样,这并不意味着(define y 1):它只被允许存在,因为 的语法\xce\xbb允许它存在。
所以在Scheme中有一些表达式,就像在Lisp中一样,它们可能包含本身不是表达式的部分,但也有一些东西(我认为它们只出现在程序的顶层?)不是表达式:它们\是定义之类的东西。
\n请注意,上面我已经将表达式讨论为在求值时具有值的东西:当然,这真正的含义是它具有零个或多个值:(values)是一个表达式,就像 一样(values 1 2)。更精确的定义可以解决这个问题。
请注意,我避免使用术语“form”:我认为可以肯定地说“form”是传统 Lisp 中的 s 表达式,但我实际上不确定,而且几乎可以肯定在Scheme 中这样说并不安全。
\n