【问题标题】:Haskell method that creates infinite list with all combinations of a given list使用给定列表的所有组合创建无限列表的 Haskell 方法
【发布时间】:2021-03-30 00:19:47
【问题描述】:

我的问题是我想创建一个给定列表的所有组合的无限列表。比如:

infiniteListComb [1,2] = [[],[1],[2], [1,1],[1,2],[2,1],[2,2], [1,1,1], ...].

其他例子:

infiniteListComb [1,2,3] = [[], [1], [2], [3], [1,1], [1,2], [1,3], [2,1],[2,2],[2,3],[3,1],[3,2],[3,3],[1,1,1], ...].

让我想起了幂集,但其中包含相同元素的列表。 我尝试了什么: 我是 Haskell 的新手。我尝试了以下方法:

infiniteListComb: [x] -> [[x]]
infiniteListComb [] = []
infiniteListComb [(x:xs), ys] = x : infiniteListComb [xs,ys] 

但这不起作用,因为它只是再次总结了我的清单。还有其他想法吗?

【问题讨论】:

  • 您尝试过的代码不起作用,因为输入完全错误(您输入了一个列表列表,但您的输入表明它应该能够输入任何值的列表) 而且它甚至没有有效的语法。
  • 模式[(x:xs),ys] 匹配列表列表,而不是项目列表。

标签: list haskell combinations infinite


【解决方案1】:

由于列表 Applicative/Monad 通过类似笛卡尔积的系统工作,因此有一个简短的解决方案,replicateM

import Control.Monad

infiniteListComb :: [x] -> [[x]]
infiniteListComb l = [0..] >>= \n -> replicateM n l

【讨论】:

  • infiniteListComb l = [0..] >>= (`replicateM` l)
  • replicateM 是如何定义的?
  • @ImkerWarze 可以追码here
  • @ImkerWarze replicateM :: Int -> m a -> m [a] 本质上是重复一个单子动作一定次数,收集中间结果。你可以find it on hackage,连同它的source code
【解决方案2】:

我们迭代地将输入列表xs 添加到一个列表中,从空列表开始,以获得不断增长的重复xs 列表的列表,我们将每个这样的列表 0,1,2 , ... xs 列出到 sequence,连接结果列表:

infiniteListComb :: [a] -> [[a]]
infiniteListComb xs  =  sequence =<< iterate (xs :) []
            -- = concatMap sequence (iterate (xs :) [])

例如

> take 4 (iterate ([1,2,3] :) [])
[[],[[1,2,3]],[[1,2,3],[1,2,3]],[[1,2,3],[1,2,3],[1,2,3]]]

> sequence [[1,2,3],[1,2,3]]
[[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3]]

> take 14 $ sequence =<< iterate ([1,2,3] :) []
[[],[1],[2],[3],[1,1],[1,2],[1,3],[2,1],[2,2],[2,3],[3,1],[3,2],[3,3],[1,1,1]]

Monad的本质是flatMap(拼接图)。

sequence 是这里真正的魔术师。相当于

sequence [xs, ys, ..., zs] =
  [ [x,y,...,z] | x <- xs, y <- ys, ..., z <- zs ]

或者在我们的例子中

sequence [xs, xs, ..., xs] =
  [ [x,y,...,z] | x <- xs, y <- xs, ..., z <- xs ]

巧合的是,sequence . replicate n 也称为replicateM n。但是我们省去了从 0 到不断增长的 n 的重复计数,而是一次将它们增长 1。

我们可以内联和融合这里使用的所有定义,包括

concat [a,b,c...] = a ++ concat [b,c...]

得出一个递归解决方案。


另一种方法,利用answer by chi

combs xs = ys where 
    ys = [[]] ++ weave [ map (x:) ys | x <- xs ] 
    weave ((x:xs):r) = x : weave (r ++ [xs])

many waysimplementweave

【讨论】:

    【解决方案3】:

    其他人已经提供了一些基本的解决方案。我将添加一个利用Omega monad

    Omega monad 自动处理无限多个选项之间的所有交错。也就是说,它使得infiniteListComb "ab" 在不使用b 的情况下不会返回["", "a", "aa", "aaa", ...]。大致上,每个选择都是以公平的方式安排的。

    import Control.Applicative
    import Control.Monad.Omega
           
    infiniteListComb :: [a] -> [[a]]
    infiniteListComb xs = runOmega go
       where
       go =         -- a combination is
          pure []   -- either empty
          <|>       -- or
          (:) <$>   -- a non empty list whose head is
             each xs  -- an element of xs
             <*>      -- and whose tail is
             go       -- a combination
    

    测试:

    > take 10 $ infiniteListComb [1,2]
    [[],[1],[1,1],[2],[1,1,1],[2,1],[1,2],[2,1,1],[1,1,1,1],[2,2]]
    

    Omega 的主要缺点是我们无法真正控制获得答案的顺序。我们只知道所有可能的组合都在那里。

    【讨论】:

      猜你喜欢
      • 2021-03-10
      • 2018-03-07
      • 1970-01-01
      • 1970-01-01
      • 2011-04-04
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 2015-01-10
      相关资源
      最近更新 更多