【问题标题】:Lazy list of binary number with k one带有 k 1 的二进制数的惰性列表
【发布时间】:2014-04-29 18:15:12
【问题描述】:

如何实现一个包含 k one0 zero 的列表列表,以及带有 的列表>k-1 one1 zero, ... , 0 onek zero 在 Haskell 中以便可以懒惰地检索它们?

例如,如果 k=3:

generate_list 3 = [[1,1,1],[0,1,1],[1,0,1],[1,1,0],[0,0,1],[0,1,0],[1,0,0],[0,0,0]]

感谢bheklilr 的建议。这是我的解决方案:

generate k = take (2^k) $ foldl (\x y -> zipWith (:) y x) (map (\x->[x]) (head rows)) (tail rows)
      where 
            rows = map cycle $ map pattern [0..k-1]
            pattern i = replicate (2^i) 1 ++ replicate (2^i) 0

但是有一个问题:

generate_list 3 = [[1,1,1], [0,1,1], [1,0,1], [1,1,0], [0,0,1], [0,1,0], [1,0,0], [0,0,0]]
generate 3 = [[1,1,1], [1,1,0], [1,0,1], [1,0,0], [0,1,1], [0,1,0], [0,0,1], [0,0,0]]

generate 3 !! 3 = [1,0,0] - it contains 1 one
generate_list 3 !! 3 = [1,1,0] - it contain 2 one

所以对于我在generate_list 中的任务顺序,输出顺序很重要,[1,1,0] 必须在[1,0,0] 之前。

【问题讨论】:

  • 到目前为止你做了什么?您能否展示您尝试过的任何代码,或者甚至说出您尝试过使用的库,例如Data.List
  • 您是否考虑过这与建立truth table 的关系?有一个非常简单的算法可以手动填写,你怎么把它变成代码?
  • 我想生成反向列表。如果我建立一个真值表并将其反转,我就会失去懒惰。
  • 如果你把真值表倒过来怎么办?

标签: list haskell binary lazy-evaluation


【解决方案1】:

使用Data.List 的一些函数,这很容易解决。我会指出你的函数应该会产生

[[1,1,1], [1,1,0], [1,0,1], [1,0,0], [0,1,1], [0,1,0], [0,0,1], [0,0,0]]

相反,它遵循模式和自然顺序。

这个问题有两个部分,生成交替的 1 和 0 并具有一定重复次数的列表(即[0, 1, 0, 1, ..][0, 0, 1, 1, 0, 0, 1, 1, ..] 等),然后将它们正确地连接在一起。

对于第一个问题,replicate 函数非常方便。您可以使用

轻松生成基本模式
replicate (2^i) 0 ++ replicate (2^i) 1

其中2^i 是重复数字的数量,因此对于i = 0,这将输出[0, 1],对于i = 3,它将输出[0, 0, 0, 0, 1, 1, 1, 1]

Data.List 中有一个函数可以将这个基本模式变成一个无限流,一遍又一遍地重复,你必须自己找到它(提示:它有类型签名[a] -> [a],和@ 987654321@)。由于该函数会生成一个无限列表,因此您必须使用take ??? 将其缩小到大小,其中??? 是要修剪到的长度。有了这个,您应该能够生成 [真值表] 的每一列,但是以 0 开头,而您希望它以 1 开头。你能弄清楚如何首先生成它们吗?

既然您有一个生成每一列的代码,您将需要一个函数来将每一列“压缩”在一起,但是内置的 zip 函数在这里不起作用,因为它们只能在一次特定数量的列表。您是否可以使用另一个可以描述为 n-way zip 的功能?

这应该可以帮助您入门,但您自己也有一些空白需要填补。如果你再次陷入困境,只需评论并说出你陷入困境的原因,但你真的应该尽可能多地自己解决这个问题。

【讨论】:

    【解决方案2】:

    如何在 Haskell 中实现 k 1 和 0 零的列表、k-1 1 和 1 零的列表、...、0 1 和 k 零的列表,以便可以懒惰地检索它们?

    编写一个函数,创建一个包含mn 零的列表。然后调用这个函数k次(用k0,然后用k-11等)和++的结果。

    【讨论】:

      【解决方案3】:

      这是一个使用应用函子的解决方案。

      generate 0 = [[]]
      generate k = (:) <$> [1,0] <*> generate (k-1)
      

      我想知道如何证明这确实是懒惰的?

      【讨论】:

      • 是的,您可以在 GHCi 中使用let x = generate 3take 3 x:print x 轻松验证这一点。您应该看到类似x = [1,1,1] : [1,1,0] : [1,0,1] : (_t1::[[Integer]]) 的输出,它告诉您它只计算x 的前三个元素。
      • 感谢:print 命令!我不知道有这样的东西存在。
      • 然而,这并不是最懒惰的。 head (generate (10^8)) 需要很长时间。有一种方法可以解决这个问题,因此无论输入有多大,它都会立即响应,留作练习 ;-)
      猜你喜欢
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 1970-01-01
      • 2011-04-05
      • 1970-01-01
      • 2012-05-05
      • 1970-01-01
      • 2021-02-24
      相关资源
      最近更新 更多