我在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);;
答案 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
)函数一起使用。