加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

7.4.2 使用聚合操作进行计算

发布时间:2020-12-14 05:42:54 所属栏目:百科 来源:网络整理
导读:7.4.2 使用聚合操作进行计算 ? ??? 聚合背后的概念在于我们保持一些状态,将在整个操作过程中传递。我们用一个初始状态开始,用给定的处理函数,为文档中的每个部件,计算一个新的状态。这种概念被反映在函数的签名中: ? val aggregateDocument : ? ('a -gt

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.net 或 http://www.manning.com/Real-WorldFunctionalProgramming。

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

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

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

?

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

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读