9

我想在 Haskell 中生成一个相当大但有限的笛卡尔积,然后我需要对其进行迭代(想想平均场模型的分区函数)。自然的事情就是使用sequence,像这样:

l = sequence $ replicate n [0,1,2]

不幸的是,对于 large n,这不适合内存,length l例如,我一请求就用完了堆。我需要一种方法来懒惰地做同样的事情。我最终“重新发现”了 base-3 算术,就像这样,

nextConfig []     = []
nextConfig (0:xs) = 1:xs
nextConfig (1:xs) = 2:xs
nextConfig (2:xs) = 0:(nextConfig xs)

ll = take (3^n) $ iterate nextConfig $ replicate n 0

(有效)但感觉就像重新发明轮子,而且它太具体了。生成产品的更好的懒惰方式是什么?

4

2 回答 2

8

与序列相比,通过以相反的顺序绑定可以获得更内存友好的方式,

foo 0 _ = [[]]
foo k xs = [h:t | t <- foo (k-1) xs, h <- xs]

由于共享较少,速度较慢,但​​由于内存是您的问题,也许对您来说已经足够了。

于 2012-04-12T12:53:52.183 回答
0

无限列表的模式是从左上角 a1 然后 a2 到 b1,a3 到 c1

a1 a2 a3 a4
b1 b2 b3 b4
c1 c2 c3 c4
d1 d2 d3 d4

也就是说,a1, a2 b1, a3 b2 c1, a4 b3 c2 d1 逗号分隔组中的字母是 a ab abc abcd和数字 1 21 321 4321

无限列表输出应该首先用 a1 对角增长,然后对角添加 2,然后对角添加 3,依此类推。

上述单个字母或数字中的任何一个都必须反向进行。

diag xs ys = [(a,b)| (m,n) <- zip (inits xs) (inits ys), (a,b) <- zip m $ reverse n ]

与每(m,n)对反向。我更喜欢一次全部反转,重复一个操作。我认为,无限列表的反向只能通过连续的反向列表来完成。

rsl = tail.scanl (flip (:)) []

take 5 $ rsl [1..]

[[1],[2,1],[3,2,1],[4,3,2,1],[5,4,3,2,1]]

然后依次处理每个列表。zip限制每次迭代中的非反转列表。

plr xs ys = [ (a,b) | ls <- rsl xs, (a,b) <- zip ls ys ]

sort.take 10.plr ['a'..] $ [1..]

[('a',1),('a',2),('a',3),('a',4),('b',1),('b',2),('b',3),('c',1),('c',2),('d',1)]

sort,因为对角取值意味着它们不像上面的第一个线性列表那样按顺序排列。sortData.List导入

顺便说一句,因为这是遍历对角三角形的数字。我take 10上面用过,三角数是:

take 11 [sum ls | ls <- rsl [1..]]

[1,3,6,10,15,21,28,36,45,55,66]
于 2021-04-06T17:41:39.007 回答