11.3.3 用函数模拟延迟计算

在F# 和C# 中计算顺序是提前的:作为给函数参数使用的表达式,在函数自身开始执行之前就计算好了。在C# 和F# 中,我们可以使用函数值模拟延迟计算,另外,F# 甚至有一个专门的关键字,支持延迟计算。

但首先,对于提前计算规则有一个例外,你肯定知道,并经常使用,但只是因为太常用,反而可能没有意识到它的特别。有些特定的C# 运算符,比如,逻辑或(||)、逻辑与(&&)、条件运算符(?:),以及空合并运算符(null-coalescing,??),能实现短路径(short-circuiting)行为,只计算那些计算结果需要的操作数。这样,我们不能很容易地实现与|| 运算符有同样行为的Or 方法:

if (Foo(5) || Foo(7))

Console.WriteLine("True");

if (Or(Foo(5), Foo(7)))

Console.WriteLine("True");

比方说,当参数小于10 时,Foo 方法返回true。这样,当计算Foo(5) 值时,内置的|| 运算符知道整体的结果肯定是true,因此,就不再计算Foo(7);相反,如果调用Or 方法,两个参数值都在方法调用前进行计算。那么,有没有办式写出这样的代码,使得如果表达式Foo(5) 的值为true 时,就不计算Foo(7) 呢?

使用函数值,可能是一个答案,即,把方法的参数类型bool,改成Func<bool>。这样,后面的代码需要这个值时,可以执行这个函数,它会再回过来计算这个表达式的值。在清单11.15 中可以看到,使用这种方法写的或操作符(现在称为LazyOr)。

清单11.18 使用函数的延迟或运算符(C#)

bool Foo(int n) {

Console.WriteLine("Foo({0})",n);    [1]

returnn <= 10;

}

bool LazyOr(Func<bool> first, Func<bool>second) {    [2]

if (first())return true;  <--计算 first 参数

if (second()) return true;   <-- 计算 second 参数

returnfalse;

}

if (LazyOr(() => Foo(5), () => Foo(7)))  <-- 只输出 Foo(5)

Console.WriteLine("True");

我们说明问题,使用Foo 方法输出到屏幕[1],因此,可以跟踪调用的过程。原始的或运算符的参数值,现在打包在lambda 函数的里面,当方法被调用时,它的参数值提前计算,但是,而现在的参数值是函数;lambda 函数内的表达式,要等到函数被调用时,才计算。

看一下LazyOr 方法[2],在需要访问布尔值,即将要计算的地方,我们调用由参数值提供的函数。如果ifrst 函数返回true,则LazyOr 方法将立即返回True,second 函数根本不会调用。这样,代码的行为就像内置的逻辑或运算符一样了。

假设我们需要访问参数值不止一次,那么,要多次调用函数吗?这听起来就不像是个非常有效的解决方案,因此,我们可能要把结果保存起来。这在F# 中,实现起来很简单,用到一个叫延迟值(lazy values)的功能。我们会先看一些F# 代码,然后,用C# 实现同样的行为;之后,我们将看一个示例应用程序,可能会对你在自己的代码中使用这种技术提供一些帮助。

时间: 2024-08-01 15:28:27

11.3.3 用函数模拟延迟计算的相关文章

11.3.1.2 Haskell 的延迟计算策略

在延迟计算策略(lazy evaluation strategy)中,函数的参数值,在函数调用时不会计算,直到后来用到这个值时才计算.我们回到前面的例子: TestAndCalculate(Calculate(10)); 在这里,Haskell 直接跳转到TestAndCalculate 函数主体.Haskell 会记住参数值的名字叫 num,如果在后面需要 num 值,就会运行 Calculate(10),然后,继续执行,得到 TestCondition的结果.如果这个函数返回true,表示需

11.3.5 为 C# 实现延迟值

11.3.5 为 C# 实现延迟值 在 11.3.3 节,我们使用函数来表示 C# 中的延迟计算.我们刚才在 F# 中探讨了Lazy<T> 类型,它为计算过的值,添加了缓存功能.从Visual Studio 2010 开始,在核心的 .NET 库下的System.Lazy <T> 就有了这种类型,因此,我们不必自己实现. 清单 11.18 是简化的 Lazy<T> 类.代码在许多方面做了简化,它不是线程安全的,不处理任何异常,只表达了核心概念. [ 清单的序号终于正常了

用缓动函数模拟物理动画

1.缓动函数简介      <1>缓动函数的动画效果是建立在CALayer层级的关键帧动画基础之上 也就是说用普通的UIView的Animation是无法直接实现缓动函数 <2>缓动函数是一系列模拟物理效果(如抛物线)方程式的统称,用以计算给定两点之间的插值 <3>两点之间插的值越多,效果越好,但是会耗费更多的性能 <4>只有理解了缓动函数的原理才有可能写出自己想要的效果 学习来自:<极客学院>之 "用缓动函数模拟物理动画"

Entity Framework 6 Recipes 2nd Edition(11-2)译 -&gt; 为一个”模型定义”函数返回一个计算列

11-3. 为一个”模型定义”函数返回一个计算列 问题 想从”模型定义”函数里返回一个计算列 解决方案 假设我们有一个员工(Employee)实体,属性有: FirstName, LastName,和BirthDate, 如 Figure 11-3所示. Figure 11-3. An Employee entity with a few typical properties 我们想要创建一个”模型定义”函数,让它返回FirstName 和LastName 合并后的full name . 我们想

5分钟模拟“透明计算”

本课程为本人参加实验楼项目课大赛5分钟模拟"透明计算"课程文档,若需转载请注明出处 透明计算相信大家都听说过,不知道的可自行百度.本实验课是一个科普实验,实验中可以学习到虚拟机及远程桌面基本概念,并自己动手搭建一个模拟透明计算的教学演示环境. 注意事项 本课只是模拟透明计算的演示效果,形似而已,绝非实现透明计算,毕竟我并不清楚透明计算的具体的技术原理.实验中选用的技术只是用来快速搭建一个通过浏览器访问的远程桌面,与透明计算没有任何关联. 5分钟是敲命令和环境配置的时间,不含文档阅读时间

2.2 函数程序的计算

在第一章,我们知道了函数程序是使用不可变数据结构,来表示数据的状态的.使一切都不可变的函数式方法,不仅影响到数据结构(在 C# 中称类),而且也扩展到局部变量. 如果你要问,当一切都不可变时,程序还能干什么,我们是不会感到惊讶的.简单的说,函数程序,不是用能够改变状态的语句来表示的,而是用计算表示的.在本节,我们会揭示这种计算方式,但首先看一个使用变量的简单代码. 2.2 函数程序的计算

利用系统函数模拟实现nginx 系统脚本启动的特殊颜色专业效果

利用系统函数模拟实现nginx 系统脚本启动的特殊颜色专业效果/etc/init.d/nginxd {start/stop/restart/reload}利用if语句实现: =========================================================== 实现特殊颜色实现效果: vim start_nginx.sh [root@lamp01 scripts]# cat bqh_nginx_startup.sh #!/bin/sh . /etc/init.d/

2019年10月1日 实现延迟计算功能

class Lazyproperty: def __init__(self,func): print('>>>>>',func) self.func=func def __get__(self, instance, owner):#self 是Lazyproperty()生成的对象 print('get方法') if instance is None: return self #如果instance 是None,就返回Lazyproperty(area)也就是self res

[py]函数中yield多次返回,延迟计算特性-杨辉三角

搞清什么是杨辉三角 每行是一个数组, 第一行: [1] 第二行: [1, 1] 第三行: [1, 2, 2, 1] ... 画的好看点就是,不过没啥卵用 1 / 1 1 / \ / 1 2 1 / \ / \ / 1 3 3 1 / \ / \ / \ / 1 4 6 4 1 / \ / \ / \ / \ / 1 5 10 10 5 1 打印杨辉三角 首先要解决一个函数,多次返回值, 我们知道py函数返回多个值,没啥问题. 但是要多次返回值呢?需要借助生成器来完成, 生成器的好处是可以保留现场