执行懒惰评估(OCaml)

时间:2013-11-17 00:22:57

标签: functional-programming ocaml lazy-evaluation

我正在尝试执行懒惰评估。


我根据lazy list函数创建了map类型。

type 'a zlist = 'a node_t lazy_t
and 'a node_t = Empty | Node of 'a * 'a zlist

let rec zlist_of_list l = lazy (
  match l with
    | [] -> Empty
    | hd::tl -> Printf.printf "transforming %d\n" hd;Node (hd, zlist_of_list tl)
)

let rec list_of_zlist zl = 
  match Lazy.force zl with
    | Empty -> []
    | Node (hd, tl) -> hd::(list_of_zlist tl)

let rec map_z f zl = lazy (
  match Lazy.force zl with
    | Empty -> Empty
    | Node (hd, tl) -> Node (f hd, map_z f tl)
)

第一个问题:

根据我的理解,lazy只是将事物封装在() behind内而不立即执行。

对于函数zlist_of_list,整个

match l with
  | [] -> Empty
  | hd::tl -> Node (hd, zlist_of_list tl)

将会延迟,在应用zlist_of_list时不执行任何位,map_z也是如此。

我是对的吗?


下面,我尝试加倍 lazy map

let f1 x = Printf.printf "%d\n" x; x

let f2 x = Printf.printf " %d\n" (-x); (-x)

let zl = zlist_of_list [1;2;3]

let zl_m2 = map_z f2 (map_z f1 zl)

let _ = list_of_zlist zl_m2

结果是

transforming 1
1
 -1
transforming 2
2
 -2
transforming 3
3
 -3

我不明白。似乎执行是按列,而不是按行。我认为应该是

  1. 首先转换每个元素
  2. 然后f1映射到每个元素
  3. f2映射到每个元素
  4. 第二个问题:

    为什么懒惰,执行顺序变得那样?

1 个答案:

答案 0 :(得分:5)

对于你的第一个问题:没错,map_z将返回计算列表下一部分的thunk,而不是列表本身。特别是,map_z定义中的递归调用在强制执行之前不会下降到列表的其余部分 - 您可以从map_z的结果中获取一个转换元素而不计算其余部分。

这也是你的第二个问题的答案:你看到一个元素被转换,然后传递给f1,然后f2的原因是你在每个步骤中从懒惰中获取一个元素列表和其他人仍然暂停。

这就是懒惰名单的重点!以这种方式做事很有用,因为它提供了一种使用无限(或非常大)列表进行编程的相当自然的方法。如果在使用元素之前必须首先计算整个列表,那么它实际上不是一个惰性数据结构。