2.2.4 用表达式代替语句

现实世界的函数编程:有 F# 和 C# 示例 1-02-02-4

2.2.4 用表达式代替语句

    在命令式语言中,表达式是简单的一段代码,可以计算并产生结果。因此,一个方法调用、任何布尔值,或整数的运算符,都是一个表达式。语句是一段代码,它影响的程序状态,没有任何结果。不返回任何值的方法调用是语句,因为它将影响程序的状态,而不管方法做什么。赋值也会更改状态(通过改变量的值),但在最简单的版本中,它不会返回任何值。

注意

    在 C# 中,赋值返回值,因此可以写 a = (b = 42);。在最简单的形式中(是这里我们正在讨论的),这是一个语句,将值赋给一个变量,而没有返回任何(如 b = 42;)。

    典型的语句的另一个例子从函数使用 return 返回,或者,使用 break 跳出循环。没有一种结构有任何的“返回值”,相反,其唯一的目的只是更改程序的状态。return 和 break 更改当前语句代码的执行(return 跳回调用这个方法的代码,break 跳转到循环结束之后)。

    如你所知,在函数语言中,状态表示函数的返回,修改状态的唯一方法是返回修改后的值。遵循这种逻辑,在函数语言中的一切都被解释为有返回值的表达式。结果可以被很好地演示,用我们前面的示例,求指定范围内数字的和。这里是代码的原始版本,它使用递归,但还不是完全的函数,因为它成了一串三条语句:

int SumNumbers(int from, int to) {
if (from > to) return 0;
int sumRest = SumNumbers(from + 1, to);
return from + sumRest;
}

    我们可以把它变成更加函数的版本,使用 C# 条件运算符 (?:)。使用此结构,我们可以重写该循环成为单个表达式,这是接近函数语言对待完全有效的代码。在 C# 中,这是可能的,只针对相对简单的示例代码,因为,我们不能在分支条件运算符中声明局部变量。

    若要演示函数语言是如何运行的,我们会写相同的方法,用并不存在“函数 C#”,正如你在清单 2.1 看到的,我们“函数 C#”唯一不标准的特点是,它允许我们在表达式内放置变量声明。

Listing 2.1 Summing numbers in the specified range in a “functional C#”

int SumNumbers(int from, int to) {
return
(from > to)
? 0
: { var sumRest = SumNumbers(from + 1, to);
from + sumRest; };
}

    若要写出只使用表达式的代码,我们要处理一些限制,因为大多数控制流结构(如条件语句或循环)是语句。即使是简约的例子,它给我们有用的提示,是能用函数语言这出什么:

    ■ 整个方法体就是一个可以返回值的表达式。在 C# 中,这意味着,方法体必须以 return 开始,此外,在代码中其它任何地方都不能使用 return,因为这将需要从一个表达式的中间跳转到这个方法的结束,而这是不可能的。

    ■ 因为 if-then-else 是语句,我们必须使用条件运算符去替换。这也意味着我们必须为两种情况提供代码(条件为真和假)。任何表达式都计算出值,但如果我们忽略了 else 分支,并且条件不成立,我们不会知道返回了什么?

    ■ else 分支中的表达式是一个代码块,包含一个变量声明,紧跟着标准的表达式。它声明的局部变量 sumRest 可以在代码块的其余部分访问。F# 中的变量声明正是通过使用这种方式。声明并不是表达式,而是一个特殊语法结构,后面是可以跟表达式的。

    我们在第3 章会回到值绑定 (F# 中等效于变量声明) ,你将看到如何在 F# 使用。F# 中的另一个显著不同的是,有一种类型,表示什么也没有。在 C# 中的 void 关键字不是一个实际类型,因此,不能声明一个 void 类型的变量。F# 的 unit 类型是一种真正的类型,只有一个值,不含有任何信息。F# 中的所有命令结构都使用此类型,所以,在调用 Console.WriteLine 方法jf ,F# 把它看作一个普通的表达式,返回 unit 类型的值。,所有的东西都是表达式的事实,使理解代码更容易。在下一节,我们将看看这个非常有趣的技术。

你可能感兴趣的:(职场,表达式,语句,休闲)