为什么要区分表达式和语句

时间:2012-12-31 06:10:13

标签: language-agnostic functional-programming procedural-programming

在函数式语言(实际上我曾经使用过)中,语句和表达式之间没有区别,每个代码块的最后一个值是块的“返回值”。另一方面,通常不被认为是纯函数的语言通常会引入这种区别。

作为我正在谈论的一个例子,以下python代码打印None

def foo():
    5 + 5
print(foo())

,而方案代码打印10

(define (foo) (+ 5 5))
(display (foo))

显然,我对那些喜欢一种风格的人的主观答案不感兴趣,而是客观原因。

对我而言,似乎这种区别使得语言的语法和实现更加复杂(一个不那么明显的例子就是c ++标准中模板和void类型的必要例外,或者引入了“shortcut if statements”,像c-affected语言中的?一样没有真正的好处 - 但很可能有一个原因,即使是新的现代语言仍然有这种区别。

3 个答案:

答案 0 :(得分:5)

无处不在的副作用。

如果你是一个纯粹的功能语言,一切都是表达。即使是“陈述”也会返回()之类的内容(可能会按类型区分,例如IO ()

但是,默认情况下,大多数编程语言都允许在任何地方或任何地方使用效果,因此排序成为关键,因此您可以使用特殊语法为计算机排序语句,通常用分号分隔。

纯表达式不是这种情况,纯表达式可以按任何保留表达式语义的顺序进行求值。

副作用动作被认为是特殊的表达式,它们会得到特殊的语法。

答案 1 :(得分:4)

首先,我想说,我认为你会问两个,或许更多不同的问题:"为什么某些表达在句法上与其他表达方式有所区别?"和"为什么用它们排序的语义是什么?"

对于你的第一个问题:我从很多事情中得到的意义是,语句表达式,但是在所有情况下都不能作为子表达式出现的受限类表达式,例如,

x = 4
y = (x += 1)

上面的python代码将生成语法错误,因为语句出现在需要(不受限制的)表达式的位置。我将语句与副作用,排序和命令式风格联系起来。我不知道你是否认为编程风格是你问题的主观答案(风格本身肯定是主观的)。

我很想听听别人的声音。也接受了这个问题。

对于第二个问题:语义有时是任意决定的,但目标是合理的语义,不同的语言设计者只是在最合理(或最期望)的内容上有所不同。让我感到惊讶的是,如果控件在Python中到达函数体的末尾,它将返回None,但这些是语义。设计师必须回答类似的语义问题,如" while循环的类型应该是什么?"和#34; if语句的类型如果没有else分支应该是什么?这些陈述在语法上应该在哪里允许(如果这样的if语句是一系列陈述中的最后一个陈述,就会出现问题)?"

答案 2 :(得分:0)

问题是,"为什么新语言仍然只有语句而不是表达式?",对吧?

编程语言设计解决了不同的问题,例如

  1. 简单的语法,
  2. 简单实施,
  3. 简单语义
  4. 是更理论化的设计目标之一,

    1. 生成的编译代码的执行速度
    2. 编译速度
    3. 执行程序的资源消耗
    4. 易用性(例如简单易读)
    5. 是更实际的......

      这些设计目标没有明确的定义,例如:一个简短的语法不一定是最清晰的结构,所以哪一个更简单?

      (考虑你的例子)

      为了便于使用或代码可读性,语言设计师可能会要求您在函数产生的值(或更确切地说是表达式)之前写回“'”。这是一份退货声明。如果你可以省略“返回”,它仍然是隐含的,它仍然可以被视为一个return语句(它在代码中不会那么明显)。如果将其视为表达式,则这意味着替换语义,例如, Scheme,但可能不是Python。从语法的角度来看,区分语句和表达是有意义的,其中“返回”和“返回”。是必需的。

      查看机器代码(我没有做太多,所以我可能错了)在我看来,只有语句,没有表达式。

      E.g。你的例子:

      ld r1, 5
      ld r2, 5
      add r3, r1, r2
      ret r3
      

      (我显然是这样做了)

      因此,对于那些喜欢考虑(von Neumann)CPU内核如何实际运行,或者想要简化这种目标架构的编译的人来说,语句就是这样。

      还有特别的邪恶' (如在非功能性中)赋值语句。表达终止循环而不递归是必需的。根据Dijkstra,循环具有比递归更简单的语义(参考E.W. Dijkstra," A Discipline of Programming" 1976)。循环执行速度更快,并且比递归消耗更少的存储空间。除非你的语言优化尾递归(比如Scheme)。