【问题标题】:List.fold order of argumentsList.fold 参数的顺序
【发布时间】:2019-09-15 17:20:08
【问题描述】:

您好,我正在尝试理解以下代码。此代码的目的是计算素数出现的次数。 factors 函数只查找给定数字的质因数。

let smallArray = Array.Parallel.init 5 factors;;

let checkMap key map =
    match Map.tryFind key map with
    | Some i -> i
    | None -> 0

let incr map (key:int) = Map.add key ((checkMap key map) + 1) map

Array.fold (List.fold incr) Map.empty smallArray;; 

我卡住的地方是代码的最后一行。我不知道它是先执行 Array.fold 还是 List.fold,但我的猜测是 List.fold。下一步是将函数 incr 应用于小数组并将其放入一个空映射中,但函数 incr 接受 2 个参数,据我所知,我们只给它一个映射?有人可以解释一下吗?

【问题讨论】:

  • 这段代码写得很混乱,很难解释。它可以简单地替换为smallArray |> Seq.concat |> Seq.countBy id |> Map
  • 我上面给出的更简单的实现对于大数组来说也快得多。我认为这是因为Seq.countBy 使用了可变数据结构(在底层是安全的),而不是对不可变映射进行多次查找和更新。

标签: .net functional-programming f#


【解决方案1】:

我们先总结一下这里涉及到的函数的类型:

List.fold : ('State -> 'T -> 'State) -> 'State -> 'T list -> 'State
Array.fold : ('State -> 'T -> 'State) -> 'State -> 'T [] -> 'State
incr : Map<int, int> -> int -> Map<int, int>

从它的类型我们可以看出,List.fold 接受一个与incr 形状相同的函数,接受两个参数并返回一个与其第一个参数相同类型的值。将incr 应用到List.fold 将产生一个具有以下类型的部分应用函数,然后替换推断类型:

(List.fold incr) : 'State -> 'T list -> 'State

在将'State'T 替换为可以从incr 的应用中推断出的类型之后,我们得到:

(List.fold incr) : Map<int, int> -> int list -> Map<int, int>

这又与incr 具有相同的形状,唯一的区别是incr 的第二个int 参数在这里是int list。由于Array.foldList.fold 具有相同的基本形状,因此我们可以像上面对incr 一样使用(List.fold incr),作为Array.fold 的第一个参数。

Array.fold (List.fold incr),如果部分应用,将产生类型:

(Array.fold (List.fold incr)) : Map<int, int> -> int list [] -> Map<int, int>

Map.emptysmallArray 然后分别作为初始值和要折叠的集合应用于最后一个参数,以便:

  • Array.fold 折叠 smallArray(List.fold incr)
  • List.fold incrsmallArray 中依次折叠每个int list
  • incr 将其结果累积在 Map&lt;int, int&gt; 中,该结果源自传递给 Array.fold 的初始 Map.empty 值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多