【问题标题】:Function that converts a sequence to a list in OCaml在 OCaml 中将序列转换为列表的函数
【发布时间】:2022-04-05 08:54:58
【问题描述】:

我想使用List.init 将序列转换为列表。我希望在每一步都检索s 的第 i 个值。

let to_list s = 
  let n = length s in 
  List.init n 
    (fun _i -> 
       match s () with
       | Nil -> assert false
       | Cons (a, sr) -> a)

这给了我一个仅使用s 的第一个元素初始化的列表。在 OCaml 中是否可以使用 s 的所有值初始化列表?

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    研究List.initdefinition可能会有所帮助。

    根据列表的大小有两种变体:尾递归的init_tailrec_aux,其结果是相反的顺序,以及基本的,init_aux。他们有相同的结果,所以我们只需要看看init_aux

    let rec init_aux i n f =
      if i >= n then []
      else
        let r = f i in
        r :: init_aux (i+1) n f
    

    此函数递归递增计数器i,直到达到限制n。对于每个严格小于限制的计数器值,它会将f i 给出的值添加到正在生成的列表的头部。

    现在的问题是,当使用不同的 i 值调用时,您的匿名函数会做什么?:

    let f_anon =
      (fun _i -> match s () with
          |Nil -> assert false
          |Cons(a, sr) -> a)
    

    不管_i,它总是给出s ()产生的列表的头部,而if s ()总是返回相同的列表,那么f_anon 0 = f_anon 1 = f_anon 2 = f_anon 3 = hd (s ()).

    Jeffrey Scofield 的 answer 描述了一种为每个 _i 赋予不同值的技术,我同意他的建议,即 List.init 不是解决此问题的最佳解决方案。

    【讨论】:

      【解决方案2】:

      问题的本质是你没有保存sr,这会让你检索序列的下一个元素。

      然而,稍大的问题是List.init 只将一个 int 作为参数传递给初始化函数。因此,即使您确实跟踪了sr,也无法将其传递给您的初始化函数。

      您可以使用 OCaml 的不纯部分做您想做的事。例如,您可以在每一步将sr 保存在全局引用变量中,并在下一次调用初始化函数时检索它。但是,这确实是一种非常麻烦的方式来生成您的列表。

      我建议不要使用List.init。你可以编写一个简单的递归函数来做你想做的事。 (如果你关心尾递归,你可以写一个稍微不那么直接的函数。)

      【讨论】:

      • 感谢您的回答,是的,我做了什么,但我想知道 init 是如何工作的,因为我之前没有使用过它,尤其是当我们想在每次不同的值时恢复时
      • 好吧,List.init 几乎只适用于可以根据它们在列表中的位置计算列表元素的情况(而不是其他情况)。由于您的情况不是这样,因此弄清楚如何使用 List.init 没有任何优势(恕我直言)。相反,也许可以尝试使用List.init 将数组转换为列表(比如)。
      • @maya 如果您要恢复的值不是0..n-1 范围内的索引整数,其中nList.init 的第一个参数,那么就像 Jeffrey 说的那样,这很自我击败。
      【解决方案3】:

      使用递归函数会增加复杂性,所以我认为直接以​​相应长度初始化列表(或数组)会更好,但我真的不知道如何像 Jeffrey Scofield 所说的那样在每个 _i 处获得不同的值我不太熟悉 ocaml,尤其是序列,所以我在做这件事时遇到了一些困难:(

      【讨论】:

      • 尝试使用下面描述的init_aux 函数并将f 替换为您的序列ss 的头部给出r,它的尾部应该传递给递归调用。
      • 使用递归不会增加复杂度。 List.init 被实现为递归函数。递归是 OCaml 中解决问题的常用方法。 (但我承认,你确实需要学会识别和使用尾递归。)
      • @maya 软提醒:请将此作为评论而不是答案发布,否则可能会被标记为稍后删除。
      猜你喜欢
      • 2021-12-15
      • 2018-03-14
      • 2018-07-22
      • 1970-01-01
      • 2015-03-20
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多