Seq展开是如何实现的

How is Seq unfold implemented

请问Seq的展开功能是如何实现的

我尝试创建自己的 Seq 模块 (My_Seq) 以查看我是否了解该功能的工作原理,但我无法让展开的行为像 Seq 的展开功能一样。

这是我的尝试(My_Seq,请注意我删除了除必要功能以外的所有功能)

module type My_Seq_Sig =
sig
  type 'a t

  val empty: 'a t
  val iter: ('a -> unit) -> 'a t -> unit
  val unfold : ('b -> ('a * 'b) option) -> 'b -> 'a t
end

module My_Seq:My_Seq_Sig =
struct
  type 'a t = unit -> 'a node
  and
    'a node =
    | Nil
    | Cons of 'a * 'a t

  let empty = fun () -> Nil

  let rec iter f s =
    match s() with
    | Nil -> ()
    | Cons (e, next) -> f e; iter f next

  let rec unfold f e =
    match (f e) with
    | None -> empty
    | Some (e, next) -> fun () -> Cons (e, unfold f next)
end

下面是我如何调用我的模块 My_Seq:

let seq =
  let line = ref 0 in
  let filename = print_string "Enter filename: "; read_line() in
  My_Seq.unfold
    (
      fun e ->
        try
          line := !line + 1;
          Some(((string_of_int !line) ^ ": " ^ (input_line e)), e)
        with
        End_of_file
        | _ ->
        print_endline("---Read->" ^ string_of_int (!line - 1) ^ "<-Line(s)---");
        close_in e;
        None
    )
    (open_in filename)

let () =
  seq |> My_Seq.iter print_endline

这是我尝试的结果:

Enter filename: datafile
1: This is the first
2: This is the second
3: This is the third
4: This is the fourth
---Read->5<-Line(s)---
5: This is the fifth

现在如果我使用 Seq 的展开功能:

let seq2 =
  let line = ref 0 in
  let filename = print_string "Enter filename: "; read_line() in
  Seq.unfold
    (
      fun e ->
        try
          line := !line + 1;
          Some(((string_of_int !line) ^ ": " ^ (input_line e)), e)
        with
        End_of_file
        | _ ->
        print_endline("---Read->" ^ string_of_int (!line - 1) ^ "<-Line(s)---");
        close_in e;
        None
    )
    (open_in filename)

let () =
  seq2 |> Seq.iter print_endline

这是使用 Seq 的展开函数的输出:

Enter filename: datafile
1: This is the first
2: This is the second
3: This is the third
4: This is the fourth
5: This is the fifth
---Read->5<-Line(s)---

数据文件内容:

This is the first
This is the second
This is the third
This is the fourth
This is the fifth

您会注意到输出不同,我不知道为什么。也许有人可以阐明这一点。

做到了 Guest0x0

let rec unfold f e =
    fun () ->(
    match (f e) with
    | None -> Nil
    | Some (e, next) -> Cons (e, unfold f next))

区别在于计算最后一个元素的时间。在你的 unfold 中,当元素 before 被获取(通过在某处提供一个单元参数)时,计算最后一个元素(在 f e 中),而 Stdlib 版本仅在获取最后一个元素时才计算该元素本身。

为了让你的 unfold 表现得像 Stdlib 一样,请注意你的 unfold returns 的两个分支都是一个以单位为参数的函数。通过将此参数提升到整个模式匹配之外,f e 的实际计算将被延迟,从而导致 Stdlib 行为