我需要创建可拆分惰性列表的函数。例如,[5; 6; 3; 2; 1]-> [5; 3; 1]和[6; 2]。这是常规列表的语法,但必须是懒惰的。函数按索引划分,第一个列表为奇数,第二个为奇数。我写这样的函数,但是我不知道如何向懒惰列表添加新元素:
let rec merge list =
let rec mergeHelp list acc = function
| LNil -> failwith "Empty list"
| LCons(x, xf) ->
if (acc mod 2 == 0)
then LCons(x, function() -> mergeHelp (acc+1) (xf())), LCons(LNil, function() -> LNil)
else LCons(LNil, function() -> LNil), LCons(x, function() -> mergeHelp (acc+1) (xf()))
in mergeHelp list 0
;;
答案 0 :(得分:2)
我不知道您的惰性列表类型是什么,但我将从您的代码中假设它看起来像:
type 'a t = LNil | LCons of 'a * (unit -> 'a t)
请注意,这与(unit -> 'a t)
为'a t lazy
的更典型的惰性列表不同。
有可能不会以生成它们的相同方式来使用这两个列表,我们也不想遍历所有功能运行的输入,而不会出现偶数的情况。因此,让我们编写一个将元素配对的函数:
let rec pair = function
| LNil -> LNil
| LCons (fst, rest) ->
match rest () with
| LNil -> LCons ((fst, None), const LNil)
| LCons (snd, rest) ->
let later_pairs = lazy (pair rest()) in
LCons ((fst, Some snd), fun () -> Lazy.force later_pairs)
此函数的类型为'a t -> ('a * 'a option) t
,其主要功能是一旦扫描了一次,由于不重新提交输出元素,因此再次进行扫描很便宜。这些类型有点令人难过,因为实际上我们只允许None
作为结果的最后一个元素中的第二个元素,但让我们忍受并继续下去。首先,我们需要一些琐碎的实用程序:
let rec map f = function
| LNil -> LNil
| LCons (a, r) -> LCons (f a, fun () -> map f (r ()))
let rec filter_map f = function
| LNil -> LNil
| LCons (x, r) ->
let r () = filter_map f (r ()) in
match f x with
| None -> r ()
| Some a -> LCons (a, r)
它们具有类型('a -> 'b) -> 'a t -> 'b t
和('a -> 'b option) -> 'a t -> 'b t
,它们在读取类型签名时会做出最愚蠢的猜测。现在,我们可以实现所需功能:
let unmerge xs =
let pairs = pair xs in
(map (fun (a,_) -> a) pairs, filter_map (fun (_,b) -> b) pairs)