11.2 测试函数式代码
无论是函数式编程,还是其他范式,都不可能完全消除错误,或阻止在修改现有代码时引入错误,这就是普遍采用单元测试背后的原因之一。好消息是,测试C# 代码时,使用的单元测试技术的大多数也都适用于F# 程序;而且,在许多方面,函数式编程和F# 的测试更容易。
为F# 选择单元测试框架
正如我们在第九章所看到的,可以用F# 写标准的类,因此,任何.NET 的...
分类:
其他好文 时间:
2015-01-07 18:57:02
阅读次数:
115
11.1.2.2 使用不可变数据结构
为了演示了以不可变风格,写相同的代码,但不一定必须使用函数式列表;即使使用标准的 List 类型,我们一样能够避免修改集合。然而,不幸的是,要确保不意外修改列表,可能很难。
处理不允许修改的类型,有更好的方法。可以使用真正不可变类型,比如,第三章的FuncList,或者 .NET Framework 中的 ReadOnlyCollection;即使使...
分类:
其他好文 时间:
2015-01-07 16:56:10
阅读次数:
132
11.1.2.1 使用可变数据结构
在清单11.4 中,可以看到两个函数,处理的集合保存了前面示例的地名。这一次,我们使用C#,把地名保存在标准的List 类型中,它是可变的。
清单11.4 处理保存在List 中的地名(C#)
List LoadPlaces() { [1]
returnnew List { "Seattle", "Prague",
"...
分类:
其他好文 时间:
2015-01-07 13:16:51
阅读次数:
131
11.1.1 重用常见的代码块
一个最好的编程实践,就是避免在多个地方重复相同的代码。如果有两个类似程序,就值得考虑把它们合并成一个;新的程序需要有新的参数,描述代码按照不同于原来的路径。
在函数式编程中,我们有一个强大的武器:函数值作为参数值使用的能力,这使得函数或者方法的参数化更容易。为了演示,假设我们有一个关于城市的信息数据库,我们要用数据生成几份报表。
我们先写一个加载数据的函...
分类:
其他好文 时间:
2015-01-06 15:36:38
阅读次数:
241
11.1 重构函数式程序
重构是许多现代开发方法的一个主要部分。在一些语言中,这种技术也支持集成开发环境(IDE),比如,Visual Studio 中的C# 编辑器。大多数重构技术是为面向对象范式而开发的,但是,我们将从函数的角度来讨论。
重构
重构是修改源代码的过程,改善设计,但不改变其含义。重构的目标是使代码更具可读性,在未来更容易修改或扩展,或者改进其结构。一个简单...
分类:
其他好文 时间:
2015-01-05 11:13:31
阅读次数:
126
第十一章重构和测试函数式程序
本章介绍
■重构函数式程序
■使用不变性推理代码
■为 F# 程序写单元测试
■使用延迟值缓存结果
这本书的主题之一就是,函数编程理如何使解代码更容易理解,只需要通过阅读就可以;特别是在需要修改陌生程序,或者通过组合现有函数实现行为,或者重构现有的代码时,尤为重要。函数式编程更容易重构,缘于清晰度和模块化:可以改善代码,并且有信心这种改变不会破...
分类:
其他好文 时间:
2015-01-04 17:15:20
阅读次数:
136
10.4 第十章小结
在这一章,我们探讨了与函数程序效率有关的问题,讨论了用函数方式处理大量数据。因为大多数函数程序使用递归实现,这一章的很大一部分就是围绕这个主题。
可以看到,使用递归的代码,一定要仔细,避免由于递归太深,引起堆栈溢出的错误。在本章开头,我们讨论了一种称为尾递归的技术,它可用来重写我们熟悉的列表处理函数(如map and filter),能避免堆栈溢出。单靠尾递归,不...
分类:
其他好文 时间:
2015-01-04 09:58:51
阅读次数:
112
10.3.2.1 使用连续处理树
要把我们以前实现的 sumTree 函数,转变成使用连续的版本,首先,要给这个函数添加一个额外的参数(连续);其次,还需要改变函数返回结果的方式,不是简单地返回值,而是把它作为参数值,给连续进行调用。 清单 10.18 是代码的最终版本。
清单 10.18 使用连续,计算树中元素的和 (F# Interactive)
> let rec sumT...
分类:
其他好文 时间:
2015-01-03 21:06:33
阅读次数:
186
10.3.2 利用连续的代码
问题是,我们既希望做尾递归调用,还要在尾递归调用完成后,再执行一些代码。这看起来是一个棘手的问题,但有一个有趣的解决方案。我们把要在递归调用完成后执行的所有代码,拿来作为参数值,提供给递归调用,这样,我们要写的函数将仅只包含一个递归调用。
可以把这个看作是另一种类型的累加器参数:我们不是累加值,而是累加“需要在以后运行的代码”。现在的问题是,我们如何能拿到其...
分类:
其他好文 时间:
2015-01-03 19:53:36
阅读次数:
140
10.3.1 树处理的难点
我们来看一个简单的处理树的例子。清单 10.15 声明了一个表示整数树的类型,并用递归函数,统计树中所有值的和。
清单 10.15 树型数据结构并计算元素的和 (F# Interactive)
> type IntTree = [1]
| Leaf of int
| Node of IntTree * IntTree;;
t...
分类:
其他好文 时间:
2015-01-03 17:26:39
阅读次数:
155