Functional programming 惰性求值(OCaml)的执行
我正试图在懒惰评估的执行下工作Functional programming 惰性求值(OCaml)的执行,functional-programming,ocaml,lazy-evaluation,Functional Programming,Ocaml,Lazy Evaluation,我正试图在懒惰评估的执行下工作 我创建了一个lazy列表类型和相应的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
我创建了一个
lazy列表
类型和相应的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
只是将事物封装在()中,而不立即执行
因此,对于函数zlist\u of_list
,整个
match l with
| [] -> Empty
| hd::tl -> Node (hd, zlist_of_list tl)
将被延迟,当应用zlist\u of_list
时,不会执行任何一位,map\u z
我说得对吗
下面,我尝试执行双重惰性映射
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
这个问题我不明白。似乎是按列执行,而不是按行执行。我想应该是的
每个元素首先被转换
然后将f1映射到每个元素
f2被映射到每个元素
第二个问题:
为什么通过lazy,执行顺序会变成这样?对于您的第一个问题:没错,map_z
将返回一个thunk,计算列表的下一部分,而不是列表本身。特别是,map_z
定义中的递归调用在强制执行之前不会下降到列表的其余部分-您可以从map_z
的结果中获取一个转换后的元素,而无需计算其余部分
这也是第二个问题的答案:您看到一个元素被转换,然后传递到f1
,然后传递到f2
的原因是,在每个步骤中,您都从惰性列表中提取一个元素,而其他元素保持挂起状态
这就是懒惰列表的全部意义!这样做很有用,因为它提供了一种相当自然的方式来编写无限(或非常大)的列表。如果在使用元素之前必须先计算整个列表,那么它就不是一个真正的惰性数据结构。对于第一个问题:没错,map_z
将返回一个thunk,计算列表的下一部分,而不是列表本身。特别是,map_z
定义中的递归调用在强制执行之前不会下降到列表的其余部分-您可以从map_z
的结果中获取一个转换后的元素,而无需计算其余部分
这也是第二个问题的答案:您看到一个元素被转换,然后传递到f1
,然后传递到f2
的原因是,在每个步骤中,您都从惰性列表中提取一个元素,而其他元素保持挂起状态
这就是懒惰列表的全部意义!这样做很有用,因为它提供了一种相当自然的方式来编写无限(或非常大)的列表。如果在使用元素之前必须先计算整个列表,那么它就不是真正的惰性数据结构