请问有人有“表达式”和“语句”的良好定义,并且它们之间的区别是什么?
表达式:能够计算出值的一种东西。例如:1+2/x
语句:执行某项操作的一行代码。例如:GOTO 100
在最早期的通用编程语言(如FORTRAN)中,这个区别非常明显。在FORTRAN中,语句是一个执行单元,是你所做的事情。之所以它不被称为“行”,仅仅是因为有时候它跨越了多行。一个独立的表达式没法做任何事情……你必须将其分配给一个变量。
1 + 2 / X
FORTRAN中的错误,因为它什么也不做。你必须对那个表达式进行某些操作:
X = 1 + 2 / X
FORTRAN并没有像我们今天所知道的语法,那个想法是作为Algol-60定义的一部分而被发明的,连同Backus-Naur Form(BNF)一起。在那时,“语义”区别(“具有值”与“执行某些操作”)已经被奉为“语法”:一种短语是表达式,另一种是语句,解析器可以将它们区分开来。
后来的语言设计者模糊了这种区别:他们允许语法表达式执行某些操作,并且允许具有值的语法语句。仍然存在的最早流行的语言示例是C语言。C语言的设计者意识到,如果允许评估一个表达式并丢弃结果,则不会造成任何伤害。在C语言中,每个语法表达式都可以通过在末尾添加分号来变成语句:
1 + 2 / x;
这虽然毫无实际效果,但是完全是真实的陈述。同样,在 C 语言中,一个表达式可能会有 副作用 — 它会改变某些东西。
1 + 2 / callfunc(12);
因为callfunc
可能会执行一些有用的操作。
一旦你允许任何表达式都可以成为语句,你也可以在表达式中使用赋值运算符(=)。这就是为什么C语言允许你做类似下面的事情:
callfunc(x = 2);
这里首先将表达式 x = 2(将值2赋给x)进行评估,然后将其(即2)传递给函数callfunc
。
在所有C派生语言中(包括C,C ++,C#和Java),表达式和语句的模糊化都存在,虽然仍有一些语句(如while
),但几乎可以将任何表达式用作语句(在C#中,只能使用赋值、调用、增量和减量表达式作为语句;请参见Scott Wisniewski的答案)。
对于具有两个“语法类别”(这是语句和表达式此类事物的技术名称)的编程语言来说,可能会导致重复劳动。例如,C有两种条件形式,其中之一是语句形式。
if (E) S1; else S2;
以及表达式的形式
E ? E1 : E2
有时人们希望存在并不存在的重复:例如,在标准C中,只有语句才能声明新的局部变量 - 但是这种能力非常有用,因此GNU C编译器提供了一个GNU扩展,使表达式也能声明局部变量。
其他语言的设计者不喜欢这种重复,并且他们很早就看到,如果表达式除了值之外还具有副作用,那么语句和表达式之间的语法区别并不是很有用 - 因此他们取消了它。 Haskell、Icon、Lisp和ML都是没有语法语句的语言 - 它们只有表达式。 即使是类结构化的循环和条件形式也被视为表达式,并且它们具有值 - 但不是非常有趣的值。
callfunc(x = 2);
把 x
传递给了 callfunc
,而不是传递了数字 2
。如果 x
是浮点数,则调用 callfunc(float)
而不是 callfunc(int)
。在 C++ 中,如果你把 x=y
传递给了 func
,并且 func
接收一个引用并对其进行更改,那么它会更改 x
,而不是 y
。 - Gabrielwhere
子句被认为是一个表达式而不是语句。
http://learnyouahaskell.com/syntax-in-functions#where - skgbanga请注意,在C中,“=”实际上是一个运算符,它有两个作用:
这是ANSI C语法的一部分。您可以看到,C没有太多不同类型的语句...程序中大多数语句都是表达式语句,即在末尾带有分号的表达式。
statement
: labeled_statement
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
;
expression_statement
: ';'
| expression ';'
;
表达式是返回值的东西,而语句则不是。
例如:
1 + 2 * 4 * foo.bar() //Expression
foo.voidFunc(1); //Statement
两者的重要区别在于表达式可以链接在一起,而语句无法链接。
foo.voidFunc(1);
是一个返回void类型值的表达式。 while
和if
是语句。 - tzotreturn
被视为子语句。 - RastaJedi关于表达式与语句的可组合性(链式调用)之间的重要差异,我最喜欢的参考资料是约翰·巴克斯的图灵奖论文:Can programming be liberated from the von Neumann style?。
命令式语言(Fortran、C、Java等)强调使用语句来构建程序,并将表达式作为一种附带思想。函数式语言则强调表达式。纯粹的函数式语言具有如此强大的表达式,以至于语句可以完全被消除。
statement:
labeled-statement
expression-statement <-- can be zero or more expressions
compound-statement
selection-statement
iteration-statement
jump-statement
declaration-statement
try-block
expression:
assignment-expression
expression "," assignment-expression
assignment-expression:
conditional-expression
logical-or-expression assignment-operator initializer-clause
throw-expression
+
、-
、*
、/
、&
、|
、&&
、||
等)throw
子句也是一种表达式表达式可以被计算得到一个值,而语句则不返回任何值(它们的类型是void)。
函数调用表达式也可以被视为语句,但除非执行环境有一个特殊的内置变量来保存返回值,否则无法检索它。
面向语句的语言要求所有过程都是语句列表。面向表达式的语言,可能所有函数式语言,都是表达式列表,或者在LISP的情况下,是表示表达式列表的一个长S表达式。
虽然两种类型都可以组合,但大多数表达式可以任意组合,只要类型匹配即可。每种语句类型都有自己组合其他语句的方式,如果它们能够这样做的话。foreach和if语句要求单个语句或所有下属语句放在一个语句块中,一个接一个地排列,除非子语句允许它们自己的子语句。
语句也可以包含表达式,其中表达式实际上不包含任何语句。一个例外是lambda表达式,它表示一个函数,因此可以包含任何函数可以包含的内容,除非语言只允许有限的lambda,比如Python的单表达式lambda。
在基于表达式的语言中,函数只需要一个单一的表达式,因为所有控制结构都返回一个值(其中很多返回NIL)。不需要return语句,因为函数中最后计算的表达式就是返回值。
null
)吗?void
不更像是 _unit type_(但其单一值无法访问)吗? - Mark Cidadevoid
是一个从不返回的函数(例如,抛出错误的函数)的返回类型,那么它就是底部类型。否则,void
是单元类型。你说得对,一个不可能分歧的语句具有单元类型。但是,一个可能分歧的语句就是底部类型。由于停机定理,我们通常无法证明一个函数不会分歧,所以我认为单元类型是虚构的。底部类型不能有值,因此它不能有一个null
的单一值。 - Shelby Moore III关于表达式语言的一些事情:
最重要的是:所有东西都返回一个值
在基于表达式的语言中,花括号和大括号没有区别,用于分隔代码块和表达式,因为所有东西都是表达式。但这并不妨碍词法作用域:例如,可以为其定义所包含的表达式以及其中包含的所有语句定义本地变量。
在基于表达式的语言中,所有东西都返回一个值。一开始可能会有点奇怪——(FOR i = 1 TO 10 DO (print i))
返回什么?
以下是一些简单的例子:
(1)
返回 1
(1 + 1)
返回 2
(1 == 1)
返回 TRUE
(1 == 2)
返回 FALSE
(IF 1 == 1 THEN 10 ELSE 5)
返回 10
(IF 1 == 2 THEN 10 ELSE 5)
返回 5
以下是一些更复杂的例子:
OpenADoor(),FlushTheToilet()
或TwiddleYourThumbs()
将返回某种平凡的值,例如OK、Done或Success。(FOR i = 1 TO 10 DO (print i))
为例,for循环的值是“10”,它会导致(print i)
表达式被评估10次,每次返回i作为字符串。最后一次返回10
,是我们的最终答案。要充分利用基于表达式的语言,通常需要稍微改变一下思维方式,因为所有东西都是表达式,所以可以内联很多东西。
以下是一个快速示例:
FOR i = 1 to (IF MyString == "Hello, World!" THEN 10 ELSE 5) DO ( LotsOfCode )
对于非表达式的替代,<c:out>
是一个完全有效的选择。
IF MyString == "Hello, World!" THEN TempVar = 10 ELSE TempVar = 5
FOR i = 1 TO TempVar DO
(
LotsOfCode
)
在某些情况下,基于表达式的代码所允许的布局对我来说感觉更自然。当然,这可能会导致疯狂。作为一种基于表达式的脚本语言MaxScript的业余项目的一部分,我设法想出了这个超长的代码行。IF FindSectionStart "rigidifiers" != 0 THEN FOR i = 1 TO (local rigidifier_array = (FOR i = (local NodeStart = FindsectionStart "rigidifiers" + 1) TO (FindSectionEnd(NodeStart) - 1) collect full_array[i])).count DO
(
LotsOfCode
)
sizeof
运算符操作数的表达式永远不会求值。begin
)或单子结构的语法糖来替换。++i + ++i
是无意义的。)Falsum
的_Noreturn any_of_returnable_types
。 严格来说,具有不可预测状态的抽象机器并不等同于“崩溃的计算机”。
{}
是一个语句。加上引号并不会改变这一点。语句是具有语义的语法结构。不存在所谓的“语义层”——您似乎在指的是执行。您说您试图准确,但您失败了。您对“投票者无知”的抱怨纯粹是以人身攻击为主;您没有关于投票者心理状态的信息。 - Jim Balter{}
被定义为一个语句。 - Jim Balter