12.5.2 写计算

12.5.2 写计算

C# 查询表达式和 F# 计算表达式,可以使用函数,以非标准方式的行为(通过返回一些一元值) ,就好像返回普通的值。我们在这一节中使用的计算类型是 ValueWrapper <T>,因此,原始函数将返回ValueWrapper <T>类型的值,而不只是 T。

实现这些函数,既可以使用另外的查询或计算表达式,也可以通过直接创建计算类型的值。有些计算表达式可以封装复杂的逻辑,所以,可能很难直接创建值。在这种情况下,我们通常写少量返回计算类型的基元,使用这些基元实现其他的一切。然而,构建 ValueWrapper <T> 类型的值并不困难。下面的代码演示如何在 C# 中实现一个方法,从控制台读一个数字,并把它打包到这个计算类型内:

ValueWrapper<int> ReadInt() {
int num = Int32.Parse(Console.ReadLine());
return new ValueWrapper<int>(num);
}

这个方法从控制台读一个数字,并把它打包到 ValueWrapper <T> 类型内。F# 版本同样简单,所以,我们不在这里讨论了。重要点是,这些基元函数是,需要知道任何类型的底层结构的唯一位置。计算的其余部分,我们只需要知道这个类型支持所有的基元(最重要的是 bind 和 return),是需要写一个查询或计算的表达式。

一旦我们定义了这个值标识符,它在 F# 中表示计算表达式(第 12.5.3 节),在 C# 中实现必要的扩展方法(第 12.5.4 节),以后,就能够轻松地处理这个类型的值。注意,我们将处理的类型并没有实现 IEnumerable<T>接口。查询语法和计算表达式符号的工作独立于序列。我们将定义了代码的含义,通过实现几个方法来处理 ValueWrapper <T> 类型。清单 12.18 显示一个代码段,使用这个基元读两个整数,并用它们执行计算。

Listing 12.18 Calculating with computation values in C# and F#

C#

F#

var v =
from n in ReadInt()
from m in ReadInt()
let add = n + m
let sub = n – m
select add * sub;

value {
let! n = readInt()
let! m = readInt()
let add = n + m
let sub = n – m
return add * sub }

在 C# 中,我们使用 from 子句提取值,在 F# 中,同样的工作使用自定义的值绑定实现的。

一旦计算完成,我们再把这个值打包到计算类型中。在 C# 中,我们使用 select 子句,在 F# 中,使用 return 基元。

正如你所看到的,在 C# 和 F# 代码的结构是颇为相似的。这段代码没有任何实际的用途,但是,它有助于我们理解非标准计算是如何工作的。唯一有趣的是,我们可以在 C# 写代码,使用 let 子句,作为单个表达式,创建一个局部变量。这个子句的行为很像 F# 的 let 绑定,所以,整个代码就是一个表达式。

在下面的讨论中,我们将更更多地关注 F# 版本,因为,它会使解释这些是如何工作的更简单。在 C# 中的查询表达式语法是为写查询量身定做的,所以,很难用于其他的计算类型。当我们实现了 F# 计算表达式之后,会再回到 C# 。

可以看到,清单 12.18 只用了两个基元。基元 bind 是用于调用计算基元的,基元 return 用于把结果打包到 ValueWrapper <int> 类型中。接下来的问题可能是,F# 编译器如何使用这两个基元解释计算表达式,我们如何实现它们。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值