5.3.3 添加类型还是函数

728 篇文章 1 订阅
349 篇文章 0 订阅

5.3.3 添加类型还是函数

 

正如我们早先提到过的,在 F# 和 C# 中,函数式数据类型 Schedule 在一个方向不可扩展:很难为事件添加新的类型。在 F# 中,困难的原因在于需要修改类型声明,如果类型在共享库中,必须重新编译这个共享库;同样,在 C# 版本中,Tag 属性使得添加新类型更困难。另一方面,这种设计也有好处,能够很容易地添加新的功能处理计划。

我们来看一下函数式和面向对象方法之间的差异,图 5.2 中的两个类层次结构表示两种可能的方法。在面向对象的版本中,所有的功能都封在虚拟方法中;函数式版本公开 Tag 属性,可用于标识表示哪一个选项值。


图 5.2 表示计划,使用通常的面向对象设计(左图),和带 Tag 属性的函数式方法(右图)

 

下面列出了我们在代码示例中所看到的函数式编程风格(FP)与通常的面向对象风格的之间的主要区别:

■函数式编程风格版本能够很容易为处理数据类型添加的新功能,只要写一个使用模式匹配的函数就能实现;但是,为类型添加新的表达很难。

■面向对象的版本添加新的类型表达很容易,只要写一个新的派生类并实现虚方法就能实现;但是,添加新的虚拟方法很难。

■在函数式编程风格版本中,一个功能的代码都在一个地方,因此,与一类计算相关的所有代码都在一个函数中。

■在面向对象版本中,一个类型的代码都在一个地方,因此,处理特定表达的所有代码都在一个类声明中。

可以发现,关键问题是我们想让添加新类型更容易,还是让添加新函数更容易。经验表明,在函数编程中,向现有类型中添加新的功能更常见。

如果你熟悉通常的设计模式,可能知道访问者模式(visitor pattern),这是处理类似差别联合一类数据结构的面向对象方法,我们在第七章讨论递归差别联合时还会谈到,因为,它通常用于处理复杂的程序数据,而不是简单的值;而是否选择差别联合,也要等到第七章才会讨论到,因为这个问题更多地与程序数据有关,但是,可以先看看补充材料“在现实世界中的差别联合”,有几个使用差别联合的例子。

 

在现实世界中的差别联合

 

使用差别联合实现类层次结构,有一个很优雅的例子,即,.NET 3.5 的 LINQ 项目引入的表达式(Expression)类型,它是用来保存表达式树,表示解析后表达式源代码的数据结构,(例如,1 + x)。对于表达式的每种类型,类型都有一个派生类,如 BinaryExpression 可以表示加法,和其他二元运算,ConstantExpression用于保存文字。类型还有一个属性类似于 Tag 属性,但它的名字是 NodeType。一般而言,每当处理某种形式的源代码,或由用户输入的简单表达式,差别联合可能是正确的选择。

使用差别联合的另一个示例,是表示数据结构,如二叉树。树既可以是带有一些值的叶子,也可能是内部节点,由两个二叉树组成的树。在函数编程中,树是经常使用的数据结构,因此,在第八、第十和第十五章中都会看到。

 

在本章,我们讨论了简单值:任何简单的表示为有限集合的可选值,应该始终选择差别联合。这是因为,对于这种值,几乎可以肯定的是想要添加新的功能,而不是添加新的类型。在函数编程中,有一种差别联合非常有用,所有的函数式语言中都有:在F# 中,称为选项(option)类型。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值