And*_*rea 4 generics containers ocaml
我是OCaml的完全初学者,但我在介绍性示例中看到的代码类似于以下内容
let sum = List.fold ~f:(+.) ~init:0.0
Run Code Online (Sandbox Code Playgroud)
在这个片段中困扰我的是显式使用List.fold
.在我所知道的大多数语言中,容器的显式类型将通过使用接口,特征或类型类来抽象,以便可以重用此代码来对数组或任何其他顺序容器求和.
什么是OCaml方式使这更通用?
更通用的解决方案是使用仿函数:
module type Foldable = sig
type 'a t
val fold : 'a t -> init:'b -> f:('b -> 'a -> 'b) -> 'b
end
module MakeSum(Container : Foldable) = struct
let sum xs = Container.fold ~f:(+.) ~init:0.0
end
Run Code Online (Sandbox Code Playgroud)
正如您可能已经注意到,这种额外的参数化带来了显着的语法开销.实际上,我们可以重用接口Core
来减少它:
module MakeSum(Container : Container.T) = struct
let sum xs = Container.fold ~f:(+.) ~init:0.0
end
Run Code Online (Sandbox Code Playgroud)
要么
module MakeSum(Container : Container.S1) = struct
let sum xs = Container.fold ~f:(+.) ~init:0.0
end
Run Code Online (Sandbox Code Playgroud)
另外,作为一个例子,您可能最感兴趣的不是对容器类型进行参数化,而是对求和运算和零值进行参数化.这个特定的例子是使用OCaml Core库中的第一类函子(另一个选项)实现的,每个容器都实现了这个函数:
(** Returns the sum of [f i] for i in the container *)
val sum
: (module Commutative_group.S with type t = 'sum)
-> t -> f:(elt -> 'sum) -> 'sum
Run Code Online (Sandbox Code Playgroud)
实际上,在您的特定情况下,即使没有仿函数,我们也可以概括,因为您不需要知道类型以实现您的代码.所以我们可以将泛型定义sum
为:
let sum fold xs = fold ~f:(+.) ~init:0.0
Run Code Online (Sandbox Code Playgroud)