枚举OCaml中两个惰性列表中可构造的所有对

时间:2010-10-19 09:19:40

标签: list ocaml lazy-evaluation

我试图使用通常的对角化思想枚举OCaml中来自两个惰性列表(第一个列表中的第一个元素,第二个列表中的第二个元素)中的元素组成的所有对的集合。根据严格的评估术语,这个想法就像是

enum [0;1;2;...] [0;1;2;...] = [(0,0);(0,1);(1;0);(0;2);(1;1);(2;2);...]

我的问题是:你怎么懒得定义这个?

我会解释到目前为止我的想法,也许这对任何试图回答这个问题的人都有帮助。但如果您已经知道答案,则无需进一步阅读。我可能走错了路。

我将懒惰列表定义为

type 'a node_t =
   | Nil
   | Cons of 'a *'a t
and 'a t = ('a node_t) Lazy.t

然后我定义了函数'seq'

let seq m =
   let rec seq_ n m max acc =
           if n=max+1
               then acc
               else (seq_ (n+1) (m-1) max (lazy (Cons((n,m),acc))))
in seq_ 0 m m (lazy Nil)

它给出了一对(x,y)对的惰性列表,使得x + y = m。这就是对角线的想法。我们首先列举所有总和为0的对,然后是所有总和为1的对,然后是总和为2的对等。

然后我定义了'enum_pair'函数

let enum_pair () = 
  let rec enum_pair_ n = lazy (Cons(seq n,enum_pair_ (n+1)))
in enum_pair_ 0

生成无限懒惰列表:由0对的惰性列表组合,与对1的懒惰列表连接,等等。

到现在为止,在我看来,我几乎就在那里。现在的问题是:我如何逐个获得实际的对?

在我看来,我必须使用某种形式的列表连接(懒惰的等价物@)。但这并不高效,因为在我的懒惰列表表示中,连接两个列表的复杂度为O(n ^ 2),其中n是第一个列表的大小。我应该寻找懒惰列表的不同表示吗?或者是否有其他方式(不使用上面的'seq'和'enum_pair')不需要列表连接?

任何帮助都会非常感激。

非常感谢, Surikator。

2 个答案:

答案 0 :(得分:1)

与此同时,我已经设法到达某个地方但是,虽然它解决了问题,但解决方案并不是很优雅。在定义了我的初始问题中定义的函数之后,我可以将附加函数'enum_pair_cat'定义为

let rec enum_pair_cat ls =
lazy(
    match Lazy.force ls with
        | Nil             -> Nil
        | Cons(h,t) -> match Lazy.force h with
                                        | Nil -> Lazy.force (enum_pair_cat t)
                                        | Cons (h2,t2) -> Cons (h2,enum_pair_cat (lazy (Cons (t2,t))))
)

此新功能可实现所需的行为。通过做

enum_pair_cat (enum_pair ())

我们得到一个惰性列表,其中列出了所描述的对。所以,这解决了这个问题。

但是,我对此并不完全满意,因为此解决方案无法扩展到更高的枚举(例如,三个惰性列表)。如果您对如何解决枚举从n个懒惰列表中取得的所有n元组的一般问题有任何想法,请告诉我!

谢谢, Surikator。

答案 1 :(得分:1)

在Haskell中你可以写:

concatMap (\l -> zip l (reverse l)) $ inits [0..]

首先,我们生成[0..]的所有初始细分:

> take 5 $ inits [0..]
[[],[0],[0,1],[0,1,2],[0,1,2,3]]

将其中一个段用反向拉开它给我们一个对角线:

> (\l -> zip l (reverse l)) [0..4]
[(0,4),(1,3),(2,2),(3,1),(4,0)]

因此,映射zip将提供所有对角线:

> take 10 $ concatMap (\l -> zip l (reverse l)) $ zipWith take [1..] (repeat [0..])
[(0,0),(0,1),(1,0),(0,2),(1,1),(2,0),(0,3),(1,2),(2,1),(3,0)]