7.4.2 使用聚合操作进行计算

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

7.4.2 使用聚合操作进行计算

 

    聚合背后的概念在于我们保持一些状态,将在整个操作过程中传递。我们用一个初始状态开始,用给定的处理函数,为文档中的每个部件,计算一个新的状态。这种概念被反映在函数的签名中:

 

val aggregateDocument :
  ('a -> DocumentPart -> 'a) -> 'a -> DocumentPart –> 'a

 

    我们使用的广义概念"一些状态"的原因是,这种状态可能是任何东西。在这个函数签名中的状态类型是一个类型参数 'a,所以,它取决于这个函数的用户。函数的后两个参数值指定要处理的文档部件(这也表示整个文档)和状态的初始值。AggregateDocument 的第一个参数值是用于处理文档部件的函数,它基于旧的状态和单个文档部件计算新状态。清单 7.17 显示了完整的实现(或许是令人惊讶的简短)。

 

Listing 7.17 Aggregation of document parts (F#)

 

let rec aggregateDocument f state docPart =
  let state = f state docPart
  match docPart with
  | TitledPart(_, part) –>
    aggregateDocument f state part
  | SplitPart(_, parts) ->
    List.fold (aggregateDocument f) state parts
  | _ –> state

 

    代码需要遍历文档中的所有部件,它在当前部件上调用这个函数,然后,以递归方式处理所有子部件。与此相关的顺序是:我们可以设计出函数,首先处理所有的子部件,然后是当前的部件。不同之处在清单 7.17 中,该函数会在树的"根"节点上调用,而在其他情况下,可能会在"叶"节点上首先调用。对我们的目的而言,这两个选项都工作正常,但对于一些高级的处理,我们可能必须考虑,想要哪一种遍历方法。

    当我们对当前部件调用这个聚合函数时,对要保存新的状态的值,使用相同的名字。新值隐藏旧值,在这里,这是一项有用的安全措施: 它意味着,在我们已经计算出新的状态以后,不会由于过失而意外使用原来的状态。接下来,我们处理可能包含子部件的部件。对于标题部件,我们以递归方式处理正文。当我们获得有子部件列表的拆分部件时,用列表上通常的聚合函数 List.fold 对它进行聚合。

    聚合对于各种操作都是可用的。下面的代码片断展示了如何使用这个操作,来统计整个文档中的单词数量:

 

let totalWords =
  aggregateDocument (fun count part –>
    match part with
    | TextPart(tx) | TitledPart(tx, _) –>
      count + tx.Text.Split(' ').Length
    | _ -> count) 0 doc

 

    我们使用作为参数值的函数只关心包含文本的部件。我们有两个这样的部件,都包含 TextContent 类型值的文本。F# 的模式匹配,使我们能够只使用有一种模式,处理两种情况。这种语法称为或模式(or-pattern),只能够用在两种模式绑定到值有相同类型的标识符的情况。在我们的例子中,只需要一个 TextContent 类型的标识符(tx)。在模式匹配的正文中,我们把这个文本拆分成使用空格分隔的单词,并加上返回数组的长度作为计数。

 

注意 

    这里有几个建议,你可以在本书的网站上找到,http://www.functional-programming.nethttp://www.manning.com/Real-WorldFunctionalProgramming

    ■ 可以使用 mapDocument 来把超过500多个字符的文本部件拆分为两列。

    ■ 可以使用聚合来收集一组用于文档的图像。

    ■ 可以实现类似筛选的操作,取一个类型为 (DocumentPart -> bool)的函数,并创建文档,只包含该函数返回 true 的部件。使用这个函数,能够从文档中删除所有的图像。

 

    我们已经看到,第二种表示便于对文档进行各种操作,特别是,如果我们首先实现了有用的高阶函数。现在,我们要回到 C#,将讨论我们刚才看到的适用于C# 编程的思想,以及它们如何与面向对象方法中众所周知的概念相关。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值