【问题标题】:Ocaml List: Implement append and map functionsOcaml List:实现追加和映射功能
【发布时间】:2010-09-30 15:42:20
【问题描述】:

我目前正在尝试扩展朋友的 OCaml 程序。这是一些数据分析所需的大量函数。由于我不是真正的 OCaml 破解者,因此我目前陷入了(对我而言)奇怪的 List 实现:

type 'a cell = Nil
    | Cons of ('a * 'a llist)
and 'a llist = (unit -> 'a cell);;

我发现这实现了某种“惰性”列表,但我完全不知道它是如何工作的。我需要基于上述类型实现一个 Append 和一个 Map 函数。有人知道怎么做吗?

任何帮助将不胜感激!

【问题讨论】:

    标签: list functional-programming map ocaml lazy-evaluation


    【解决方案1】:
    let rec append l1 l2 = 
        match l1 () with
            Nil -> l2 | 
            (Cons (a, l)) -> fun () -> (Cons (a, append l l2));;
    
    let rec map f l =
        fun () -> 
            match l () with
                Nil -> Nil | 
                (Cons (a, r)) -> fun () -> (Cons (f a, map f r));;
    

    这种惰性列表实现的基本思想是,每个计算都通过 fun () -> x 封装在一个函数中(技术术语是闭包)。 只有当函数应用于 ()(单位值,不包含任何信息)时,才会计算表达式 x。

    【讨论】:

      【解决方案2】:

      注意函数闭包本质上等同于惰性值可能会有所帮助:

      lazy n : 'a Lazy.t    <=>    (fun () -> n) : unit -> 'a
      force x : 'a          <=>    x () : 'a
      

      所以'a llist 类型等价于

      type 'a llist = 'a cell Lazy.t
      

      即惰性单元格值。

      根据上述定义,地图实现可能更有意义

      let rec map f lst =
        match force lst with
          | Nil -> lazy Nil
          | Cons (hd,tl) -> lazy (Cons (f hd, map f tl))
      

      将其转换回闭包:

      let rec map f lst =
        match lst () with
          | Nil -> (fun () -> Nil)
          | Cons (hd,tl) -> (fun () -> Cons (f hd, map f tl))
      

      与追加类似

      let rec append a b =
        match force a with
          | Nil -> b
          | Cons (hd,tl) -> lazy (Cons (hd, append tl b))
      

      变成

      let rec append a b =
        match a () with
          | Nil -> b
          | Cons (hd,tl) -> (fun () -> Cons (hd, append tl b))
      

      我通常更喜欢使用 lazy 语法,因为它更清楚发生了什么。

      另外请注意,延迟挂起和关闭并不完全等效。例如,

      let x = lazy (print_endline "foo") in
        force x;
        force x
      

      打印

      foo
      

      let x = fun () -> print_endline "foo" in
        x ();
        x ()
      

      打印

      foo
      foo
      

      不同之处在于force只计算一次表达式的值。

      【讨论】:

        【解决方案3】:

        是的,列表可以是无限的。其他答案中给出的代码将附加到无限列表的末尾,但是您没有可以编写的程序可以观察无限列表后面附加的内容。

        【讨论】:

          猜你喜欢
          • 2020-08-08
          • 1970-01-01
          • 2018-08-02
          • 2011-08-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-10-31
          • 1970-01-01
          相关资源
          最近更新 更多