12.5.2 写计算

来源:互联网 发布:mac运行exe文件 编辑:程序博客网 时间:2024/06/08 02:04

12.5.2 写计算

 

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

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

 

ValueWrapper<int> ReadInt() { 

  int num =Int32.Parse(Console.ReadLine()); 

  return newValueWrapper<int>(num); 

}

 

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

我们定义好值标识符,即,在 F# 中表示为计算表达式(第 12.5.3 节),在 C# 中实现必要的扩展方法(第 12.5.4 节)以后,就能够轻松地处理这个类型的值了。注意,我们将使用的类型并没有实现 IEnumerable<T> 接口。查询语法和计算表达式的表示方法与序列无关,定义代码的含义,是通过一组使用 ValueWrapper <T> 类型的方法实现的。清单 12.18 的代码段,使用基本操作读两个整数,再进行计算。

 

清单 12.18 在 C# 和 F# 中用计算值进行计算

 

C#

F#

var v = 

  from n in ReadInt()   | [1]

  from m in ReadInt()   |

  let add = n + m 

  let sub = n – m 

  select add * sub;  [3]

value { 

  let! n = readInt()   | [2]

  let! m = readInt()   |

  let add = n + m 

  let sub = n – m 

  return add * sub }  [4]

 

在 C# 中,我们使用 from 子句提取值[1],而在 F# 中,我们是用自定义的值绑定实现的[2]。

计算完成以后,我们再把值打包到计算类型中。在 C# 中,使用 select 子句[3],在 F# 中,使用 return 基本操作[4]。

可以发现,C# 和 F# 代码的结构非常相似。这段代码并没有任何实际的用途,但是,它有助于我们理解非标准计算是如何运行的。唯一有意义的地方,是我们在 C# 写的代码,可以使用 let 子句,作为一个表达式,创建局部变量,这个子句很像 F# 中的 let 绑定,所以,整个代码就是一个表达式。

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

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

0 0
原创粉丝点击