Haskell:列表的副产品与另一个列表的子序列

时间:2013-08-09 12:05:12

标签: list haskell

我还有另外一个关于从各种来源生成列表的问题。

更新:简化示例

我有一个变量列表

["a", "b", "c"] 

和bool值

[False, True].

现在我想要一个列表,其中变量列表的所有子序列都与值列表交叉,因此对于每个条目,变量的子序列列表都包含一组与每个可能值的对。

对于上面的列表,我会得到这个(这个场景的完整列表)。由于空列表不会很好地与其他列表配对,我不关心它是否是结果列表的一部分(可以稍后添加)。

[
    [], 
    [("a", False)], 
    [("a", True)], 
    [("b", False)], 
    [("b", True)], 
    [("c", False)], 
    [("c", True)],
    [("a", False), ("b", False)],
    [("a", False), ("b", True)],
    [("a", True), ("b", False)],
    [("a", True), ("b", True)],
    [("a", False), ("c", False)],
    [("a", False), ("c", True)],
    [("a", True), ("c", False)],
    [("a", True), ("c", True)],
    [("b", False), ("c", False)],
    [("b", False), ("c", True)],
    [("b", True), ("c", False)],
    [("b", True), ("c", True)],
    [("a", False), ("b", False), ("c", False)],
    [("a", False), ("b", False), ("c", True)],
    [("a", False), ("b", True), ("c", False)],
    [("a", False), ("b", True), ("c", True)],
    [("a", True), ("b", False), ("c", False)],
    [("a", True), ("b", False), ("c", True)],
    [("a", True), ("b", True), ("c", False)],
    [("a", True), ("b", True), ("c", True)],
]

如果它只是排列,那么对排列的调用与理解相结合就足够了,但我不知道如何轻松获得子顺序的列表。 我可以使用“调用排列+理解” - 在不同大小的列表上使用 - 但听起来不是很优雅。

对此有直接的解决方案吗?

4 个答案:

答案 0 :(得分:3)

import Control.Monad (forM)
import Data.List (subsequences)

solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = do
    sequence <- subsequences variables
    forM sequence $ \variable -> do
        value <- values
        return (variable, value)

证明它有效:

>>> mapM_ print $ solution ["a", "b", "c"] [False, True]
[]
[("a",False)]
[("a",True)]
[("b",False)]
[("b",True)]
[("a",False),("b",False)]
[("a",False),("b",True)]
[("a",True),("b",False)]
[("a",True),("b",True)]
[("c",False)]
[("c",True)]
[("a",False),("c",False)]
[("a",False),("c",True)]
[("a",True),("c",False)]
[("a",True),("c",True)]
[("b",False),("c",False)]
[("b",False),("c",True)]
[("b",True),("c",False)]
[("b",True),("c",True)]
[("a",False),("b",False),("c",False)]
[("a",False),("b",False),("c",True)]
[("a",False),("b",True),("c",False)]
[("a",False),("b",True),("c",True)]
[("a",True),("b",False),("c",False)]
[("a",True),("b",False),("c",True)]
[("a",True),("b",True),("c",False)]
[("a",True),("b",True),("c",True)]

答案 1 :(得分:1)

solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = do
  as <- subsequences variables
  bs <- forM as $ const values
  zip as bs

并证明它有效:

Data.List Control.Monad Prelude> :{
Data.List Control.Monad Prelude| let solution :: [a] -> [b] -> [[(a, b)]]
Data.List Control.Monad Prelude|     solution variables values = do
Data.List Control.Monad Prelude|       as <- subsequences variables
Data.List Control.Monad Prelude|       bs <- forM as $ const values
Data.List Control.Monad Prelude|       return $ zip as bs
Data.List Control.Monad Prelude| :}
Data.List Control.Monad Prelude> solution [ "a", "b", "c" ] [ False, True ]
[[],[("a",False)],[("a",True)],[("b",False)],[("b",True)],[("a",False),("b",False)],[("a",False),("b",True)],[("a",True),("b",False)],[("a",True),("b",True)],[("c",False)],[("c",True)],[("a",False),("c",False)],[("a",False),("c",True)],[("a",True),("c",False)],[("a",True),("c",True)],[("b",False),("c",False)],[("b",False),("c",True)],[("b",True),("c",False)],[("b",True),("c",True)],[("a",False),("b",False),("c",False)],[("a",False),("b",False),("c",True)],[("a",False),("b",True),("c",False)],[("a",False),("b",True),("c",True)],[("a",True),("b",False),("c",False)],[("a",True),("b",False),("c",True)],[("a",True),("b",True),("c",False)],[("a",True),("b",True),("c",True)]]
Data.List Control.Monad Prelude> forM_ it print
[]
[("a",False)]
[("a",True)]
[("b",False)]
[("b",True)]
[("a",False),("b",False)]
[("a",False),("b",True)]
[("a",True),("b",False)]
[("a",True),("b",True)]
[("c",False)]
[("c",True)]
[("a",False),("c",False)]
[("a",False),("c",True)]
[("a",True),("c",False)]
[("a",True),("c",True)]
[("b",False),("c",False)]
[("b",False),("c",True)]
[("b",True),("c",False)]
[("b",True),("c",True)]
[("a",False),("b",False),("c",False)]
[("a",False),("b",False),("c",True)]
[("a",False),("b",True),("c",False)]
[("a",False),("b",True),("c",True)]
[("a",True),("b",False),("c",False)]
[("a",True),("b",False),("c",True)]
[("a",True),("b",True),("c",False)]
[("a",True),("b",True),("c",True)]

答案 2 :(得分:0)

生成给定列表的所有子序列(不考虑性能)的简单解决方案是:

subs :: [a] -> [[a]]
subs []      =  [[]]
subs (x:xs)  =  subs xs ++ map (x:) (subs xs)

答案 3 :(得分:0)

实际上这里没有必要使用monad。以下可能有点令人生畏,但我会在事后解释。注意:映射和折叠有助于编译器更快地编写代码。

solution :: [a] -> [b] -> [[(a, b)]]
solution variables values = foldr (<*>) [[]]
  $ map (\variable -> id : map (\value -> (:) (variable, value) ) values)
  $ variables

需要Control.Applicative

我们的想法是选择子序列并将所有可能的值分配为单个进程。函数(\value -> (:) (variable, value) ) :: b -> [(a,b)]->[(a,b)]接受一个值,与变量成对,并生成一个函数,将该对附加到变量值对列表。

通过在所有值列表上进行映射,我们得到一个函数列表map (\value -> (:) (variable, value) ) values :: [[(a,b)]->[(a,b)]]。外部列表括号用于非确定性,而内部用于绑定列表。

我们添加了另一个选项:不分配值。这是由id :: [(a,b)]->[(a,b)]完成的,它被添加到可能性列表中。

下一个lambda-abstraction-and-map构造考虑了不同的变量:我们想要列出每个变量的可能变化。

map (\variable -> (id : map (\value -> (:) (variable, value) ) values)) variables

具有类型[[[(a,b)]->[(a,b)]]],其中最外面的列表用于要绑定的变量,非确定性的中间层和已绑定的变量的内部列表。

然后最后来了:折叠!折叠在最外面的列表层上工作(每个变量做一些事情),这个列表级别消失。 (<*>)结合了所有非确定性,它是之前列表的中间层,是结果的外层。内层不受影响。折叠的起始值为[[]]::[[(a,b)]]

如果你习惯了Alternative界面的非确定性,你可能更喜欢

solution :: Alternative f => [a] -> f b -> f[(a, b)]
solution variables values = foldr (<*>) (pure [])
  $ map (\variable -> pure id <|> pure (\value -> (:) (variable, value)) <*> values)
  $ variables

因为现在列表操作(:)map用于变量列表,而有关非确定性的所有内容都由应用/替代接口处理。