迭代器,枚举和序列之间的区别

时间:2018-04-19 13:20:42

标签: ocaml

我想了解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

我对迭代器没有任何了解

2 个答案:

答案 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函数应用于集合中的所有元素。”

有什么区别?

基于拉动和基于推动的方法之间的一个关键区别是它们的表现力。考虑到您有两个生成器gen1gen2,可以轻松添加它们:

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(某些已知的containersarrayslistssetsmaps等)

迭代器是一个函数,它将相同的函数应用于container的每个元素。因此,您将拥有map迭代器,该函数将函数应用于每个元素,但保持结构不变(例如,向列表l:List.map (fun e -> e + 1) l的每个元素添加1)。 fold运算符,它将函数应用于每个元素和累加器并返回累加器(例如,添加列表l的每个元素并返回结果:List.fold_left (fun acc e -> acc + e) l)。

所以,

  • 枚举和序列:结构
  • 迭代器:对结构的每个元素起作用