嵌套的fold_left如何工作?什么是〜f:和〜init:?

时间:2019-07-16 03:55:01

标签: ocaml

我在Ocaml中有此代码段,摘自here。我知道它用指定的值填充需求(流量矩阵)的数据结构,并且当两个主机相同时,只用0填充值。在python或任何命令式语言中,我们将两个用于循环一在另一个里面做任务。我认为这就是我们在此代码中有两个(fold_left)的原因,其中每个一个都等同于一个for循环(我可能会误解!)。我的问题是这段代码如何工作? 〜f:和〜init:是什么?这些标签。如果它们是标签,为什么当我删除它们或更改它们时编译器会抱怨?即使我以正确的顺序放置这些参数? 我已经完成了一本书,并观看了许多youtube视频,但是仍然很难理解大多数Ocaml代码。

let create_3cycle_input () =
 let topo = Net.Parse.from_dotfile "./data/topologies/3cycle.dot" in
  let hosts = get_hosts topo in
   let demands =
     List.fold_left
     hosts
     ~init:SrcDstMap.empty
     ~f:(fun acc u ->
      List.fold_left
        hosts
        ~init:acc
        ~f:(fun acc v ->
            let r = if u = v then 0.0 else 53. in
            SrcDstMap.set acc ~key:(u,v) ~data:r)) in
(hosts,topo,demands);;

1 个答案:

答案 0 :(得分:1)

请阅读我的another SO answer,其中解释了fold_left的工作方式。一旦了解了单折的工作原理,我们就可以移至嵌套的纸箱(以及标签)。

当您有一个集合的集合时,即一个集合元素本身就是另一个集合,并且您想要遍历那些内部集合的每个元素而不需要嵌套折叠。一个很好的例子是可以看作向量的集合的矩阵,其中向量本身也是集合。

迭代算法很简单

state := init
for each inner-collection in outer-collection do
   for each element in inner-collection do
      state := user-function(state, element)
   done
 done

或者,在OCaml中也一样(使用折叠的Core版本)

let fold_list_of_lists outer ~init ~f =
  List.fold outer ~init ~f:(fun state inner -> 
    List.fold inner ~init:state ~f:(fun state elt ->
       f state elt)

此函数的类型为'a list list -> init:'b -> f:('b -> 'a -> 'b) -> 'b 并将适用于任何列表列表。

关于标签及其去除。标签是关键字参数,并允许以任意方式将参数传递给函数,当您拥有太多参数时,这非常有用。有时可以删除标签,但可以使用编译器选项禁用它。而且,Core库(您所引用的项目所使用的库)正在禁止删除标签,这可能是出于良好的缘故。

通常,如果整个应用程序都可以省略标签,即返回的值本身不是函数。由于fold_left返回一个类型变量,它始终可以是一个函数,因此我们始终需要将标签与Core的List.fold(和List.fold_left)函数一起使用。