1.4.2.1 阅读函数式程序

我们在清单 1.1 中看过一个示例,就是使用了不可变类型,我们的结论是,不可变类型使代码更具可读性。在本节,我们将考虑两段代码,可以用在我们函数式游戏中。

清单 1.8 中有两个示例,都涉及两个游戏角色(player 和 monster)。第一个示例说明怪物[1] [ 原文中的 AI,应该就是这个 1 ]如何移动一步,然后,判断玩家是否正处于危险之中,第二示例演示如何射击。

Listing 1.8 Code snippets form a functionalgame (C#)

var movedMonster = monster.PerformStep();       [1]

var inDanger = player.IsCloseTo(movedMonster);    [2]

(...)

var hitMonster =monster.HitByShooting(gunShot);  [3]

var hitPlayer =player.HitByShooting(gunShot);      [4]

(...)

代码的第一部分,执行怪物走一步[1],得到怪物的新状态,然后,判断玩家是否接近计算后怪物的位置;

第二部分处理虚拟环境中的射击,代码创建一个值,表示更新后的怪物[3],另一个值,表示玩家新有状态[4]。

我们这个函数式游戏中的所有对象都是不可变的,所以,当调用对象的方法时,不能修改这个对象和其他对象。如果我们理解了这一点,那么,对前面的例子就能得到几点看法。在第一段,我们首先调用怪物的 PerformStep 方法[1],该方法返回一个新的怪物,我们把它指定给变量 movedMonster;在下一行[2],我们检查玩家是否靠近这个怪物,而因此处于危险之中。

我们可以看到第二行代码依赖于第一个。如果我们改变这两行代码的顺序,程序不能编译,因为 movedMonster 没有在第一行中声明。

如果以命令式风格实现,该方法通常不会返回任何结果,它只会修改怪物对象的状态。在这种情况下,我们可以改变代码的顺序,代码可以编译,但它会更改了程序的含义,程序的行为不正确。

当游戏中射击发生时,会修改健康值,第二段的两行代码,用更新后的属性创建了新怪物[3]和新玩家[4]对象。这两行代码是独立的,因此,我们可以改变其顺序。那么,这个操作会改变程序的意思吗?看来它不应该,所有对象都是不可变的,就不会改变。令人惊讶的是,在命令式版本中,如果 gunShot 是可变的,就可能改变其意思。这些对象中的第一个可能会改变 gunShot 的一些属性,其行为是取决于两个语句的顺序。

清单1.8 相当简单,但它已表明不可变性能够消除很多可能的困难。在下一节,我们将看另一个重要的示例,但现在我们了解一下在这本书后面的一些内容。

重构和单元测试

如你所知,不可变性有助于我们理解程序做什么,因此,有助于重构代码。另一有意义的函数式重构正在改变代码的执行,程序的代码既可能在第一次到达时运行,也可能会延迟,在需要结果时才执行。不可变性对 F# 程序的开发方式非常重要,同样也使 C# 中的重构变得更容易。我们将在第十一章讨论重构。

不可变性的另一个优势体现在为函数式程序创建单元测试。因为不可变性,方法能做的唯一的事情就是返回结果,因此,我们唯一要测试的是,针对给定的参数,方法是否返回正确的结果。这一主题也会在第十一章讨论。

我们在讨论函数式编程更有效时,曾提到过不可变性对于更容易地写并行程序,非常重要。在下一节,我们将作简要探讨这一主题,以及其他相关主题。

时间: 2024-10-11 05:38:47

1.4.2.1 阅读函数式程序的相关文章

第十一章 重构和测试函数式程序

第十一章重构和测试函数式程序 本章介绍 ■重构函数式程序 ■使用不变性推理代码 ■为 F# 程序写单元测试 ■使用延迟值缓存结果 这本书的主题之一就是,函数编程理如何使解代码更容易理解,只需要通过阅读就可以:特别是在需要修改陌生程序,或者通过组合现有函数实现行为,或者重构现有的代码时,尤为重要.函数式编程更容易重构,缘于清晰度和模块化:可以改善代码,并且有信心这种改变不会破坏程序的其他部分. 正如在函数式编中的很多事情一样,修改代码而不改变其含义的思想,与数学密切相关,因为不改变表达式含义的操作

[原创译书] JS函数式编程 2.3 函数式程序员的工具集

?? Functional Programming in Javascript 主目录第二章 函数式编程基础上一节 与函数共舞 函数式程序员的工具集 如果你仔细看了到目前为止出现过的示例代码,你会发现这里面的一些方法不太熟悉. 它们是map().filter()和reduce()函数,它们对任何语言的函数式编程都至关重要. 它们可以让你不必使用循环和语句,写出更简洁的代码. map().filter()和reduce()函数组成了函数式程序员工具集的核心部分,这个工具集包括一系列纯的. 高阶的函

阅读下面程序,请回答如下问题:

问题1:这个程序要找的是符合什么条件的数? 问题2:这样的数存在么?符合这一条件的最小的数是什么? 问题3:在电脑上运行这一程序,你估计多长时间才能输出第一个结果?时间精确到分钟(电脑:单核CPU 4.0G Hz,内存和硬盘等资源充足). 问题4:在多核电脑上如何提高这一程序的运行效率? (注:该程序用C#语言编写,但是只要有C语言基础完全没有阅读压力,如果对部分语句不懂请自行查询) using System; using System.Collections.Generic; using Sy

11.1 重构函数式程序

重构是许多现代开发方法的一个主要部分.在一些语言中,这种技术也支持集成开发环境(IDE),比如,Visual Studio 中的C# 编辑器.大多数重构技术是为面向对象范式而开发的,但是,我们将从函数的角度来讨论. 重构 重构是修改源代码的过程,改善设计,但不改变其含义.重构的目标是使代码更具可读性,在未来更容易修改或扩展,或者改进其结构.一个简单的重构例子是重命名方法,使名字更具描述性:另一个例子是,把一段代码转换成方法,实现重用,以避免代码重复. 有了重构,我们首先写出能运行的代码,然后,再

阅读《程序员修炼之道-从小工到专家》阅读笔记02

这两周我们小组进入了冲刺阶段的实训,这周我读了<程序员修炼之道>第三章的内容. 靠巧合编程 怎样靠巧合编程 一开始就不知道它为什么能工作.实现的偶然: 因为代码现在的编写方式才得以发生的事情.最后会依靠没有记入文档的错误或是边界条件.它也许不是真的能工作--它也许只是看起来能工作.你依靠的边界条件也许只是一个偶然. 没有记入文档的行为可能会随着库的下一次发布而变化.多余的和不必要的调用会使你的代码变慢.多余的调用还会增加引入它们自己的新bug的风险. 结论? 对于你编写给别人调用的代码,良好的

阅读《程序员修炼之道-从小工到专家》阅读笔记01

第一章写的是注重实效的哲学,那注重失效的程序员的特征是什么?我们觉得是他们处理的问题,寻求解决方案时的态度,风格,哲学,能够越出直接的问题去思考,总是设法把问题放在更大的语境中,他们成功的另一关键是他们对他们所做的每一件事情负责. “我的代码让猫给吃了”是什么意思呢?就是注重实效的程序员对他们的职业生涯负责,不害怕承认无知或者错误,这肯定并非编程最令人愉悦的方面,但是它肯定会发生--即使在最好的项目中,彻底的测试,良好的文档,还是会出现错误,交付晚了,出现了未曾预见的技术问题.而我们应该怎么解决

阅读一个程序员的生命周期有感

博主在程序员这条路上付出了很多努力,肩负着家庭的压力,生活的压力,经济的压力,博主刚开始时,有着年轻人的激情,为公司的工作去奋斗.但是作为一个程序员,工资不是很高的情况下,只能另谋出路,虽然在公司里发展得还可以.这同时也是众多程序员的真实写照,这也是 一种无奈,青春每个人都会怀揣属于自己梦想,但是现实往往会让人屈服.如果我处在博主当时的情况,我想我的选择也是一样的.人生充满不确定性,当时正如博主所说“生活在于选择,那怕选择错了,过山车也会从谷底爬上顶峰的”,我们要勇敢去选择,勇敢去做

Java阅读word程序说明文件

完成office文件操作可以帮助apache.poi包(我用poi-3.10-FINAL),导入对应的jar包(最好所有导入) 以下的程序演示了一些操作word的过程,具体的函数功能能够查看此包的官方API import java.io.*; import org.apache.poi.POIXMLDocument; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.hwpf.extractor.*; import or

Source Insight 阅读Matlab程序

<span style="font-size:14px;">step 1: add "matlab" language: (1) options -> Preferences -> language ->Add : enter "matlab" (2) select "matlab" in the "Language" tab -> Import : import fil