我想了解ocaml中的迭代器,枚举和序列之间的区别
enumeration:
type 'a t = {
mutable count : unit -> int; (** Return the number of remaining elements in the enumeration. *)
mutable next : unit -> 'a; (** Return the next element of the enumeration or raise [No_more_elements].*)
mutable clone : unit -> 'a t;(** Return a copy of the enumeration. *)
mutable fast : bool; (** [true] if [count] can be done without reading all elements, [false] otherwise.*)
}
sequence:
type 'a node =
| Nil
| Cons of 'a * 'a t
and 'a t = unit -> 'a node
我对迭代器没有任何了解
答案 0 :(得分:9)
BatEnum
(你所谓的“枚举”,但让我们使用模块名称)或多或少地与生成器同构,这通常被称为基于拉式:
generator : unit -> 'a option
这意味着“每次调用generator ()
时,我都会从集合中提供一个新元素,直到没有更多元素并返回None
”。请注意,这意味着以前的元素无法访问。这种行为称为“破坏性”
这类似于gen库。这些迭代器从根本上讲是非常必要的(它们通过维持当前状态来工作)。
基于拉的方法不一定具有破坏性,这是Seq
类型适合的地方。它是一个类似列表的结构,除了每个节点都隐藏在一个闭包后面。它类似于懒惰列表,但没有保证持久性。您可以通过模式匹配来操纵这些序列,就像它们一样。
type 'a node =
| Nil
| Cons of 'a * 'a seq
and 'a seq = unit -> 'a node
sequence之类的迭代器也表示“基于推送”,其类型与您在许多数据结构中找到的iter
函数类似:
iterator : ('a -> unit) -> unit
表示“iterator f
会将f
函数应用于集合中的所有元素。”
基于拉动和基于推动的方法之间的一个关键区别是它们的表现力。考虑到您有两个生成器gen1
和gen2
,可以轻松添加它们:
let add gen1 gen2 =
let gen () =
match gen1(), gen2() with
| Some v1, Some v2 -> Some (v1+v2)
| _ -> None
in
gen
但是,您无法使用大多数基于推送的方法(例如sequence
)编写此类函数,因为您无法完全控制迭代。
另一方面,基于推送的迭代器通常更容易定义并且更快。
从OCaml 4.07开始,标准库中提供了Seq
。您现在可以使用seq
兼容性软件包,并在关联的oseq库中使用大型组合器库。
Seq
快速,富有表现力且相当容易使用,因此我建议使用它。
答案 1 :(得分:1)
枚举不是你写的,你只是在这里定义了一个记录。枚举是一种包含多个构造函数的类型,但变量一次只能选择一个值(您可以在C中将其视为联合类型):
type enum = One | Two | Three
let e = One
在编写序列时,序列只是一个递归枚举类型(在您的情况下,您定义了通常称为列表的内容)。
为了简化,让我们调用包含相同类型的一些元素的特殊结构container
(某些已知的containers
是arrays
,lists
, sets
,maps
等)
迭代器是一个函数,它将相同的函数应用于container
的每个元素。因此,您将拥有map
迭代器,该函数将函数应用于每个元素,但保持结构不变(例如,向列表l:List.map (fun e -> e + 1) l
的每个元素添加1)。 fold
运算符,它将函数应用于每个元素和累加器并返回累加器(例如,添加列表l的每个元素并返回结果:List.fold_left (fun acc e -> acc + e) l
)。
所以,