【问题标题】:Generating all the combinations of a set of boolean variables in Haskell在 Haskell 中生成一组布尔变量的所有组合
【发布时间】:2015-06-25 00:23:54
【问题描述】:

我正试图绕着haskell 中的列表单子低头。我试图在给定一个指定布尔变量的字符串列表的情况下生成所有可能命题的列表。

例如调用:

mapM_ print $ allPropositions ["a","b"]

会产生以下结果:

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

我已经设法通过以下代码使用列表推导和递归来做到这一点

allPropositions :: [String] -> [[(String,Bool)]]
allPropositions [] = [[]]
allPropositions (x:xs) = [(x,True):r | r <- allPropositions xs] ++ [(x,False):r | r <- allPropositions xs]

我正在寻找一种方法来使用类似于以下 sn-p 的 do 表示法,但输入数量可变。有没有办法做到这一点(嵌套单子,...)?

allPropositions' = do
    a <- [True, False]
    b <- [True, False]
    return([("a",a),("b",b)])

【问题讨论】:

    标签: list haskell list-comprehension monads


    【解决方案1】:

    你需要的是sequence :: Monad m =&gt; [m a] -&gt; m [a]

    特别是,对于 [] monad,sequence 获取 n 列表的列表,并生成所有 n-length 列表,一次从每个列表中提取一个元素。

    sequence [ [1,2,3], [4,5], [6] ] = 
       [ [1,4,6], [1,5,6], [2,4,6], [2,5,6], [3,4,6], [3,5,6] ]
    

    这对您的特定情况很有帮助,因为如果您有一个 n 字符串列表,您可以轻松地为每个字符串生成可能性:

    map (\s -> [(s,True), (s,False)] ["a", "b", "c"] = 
       [ [("a", True), ("a", False) ]
       , [("b", True), ("b", False) ]
       , [("c", True), ("c", False) ]
       ]
    

    现在您只需从每个列表中选择一个,即可让您的命题为每个变量保留一个真值:

    sequence (map (\s -> [(s,True), (s,False)] ["a", "b", "c"]) = 
       [ [("a", True), ("b", True), ("c", True)]
       , [("a", True), ("b", True), ("c", False)]
       , [("a", True), ("b", False), ("c", True)]
       , [("a", True), ("b", False), ("c", False)]
       , [("a", False), ("b", True), ("c", True)]
       , [("a", False), ("b", True), ("c", False)]
       , [("a", False), ("b", False), ("c", True)]
       , [("a", False), ("b", False), ("c", False)]
       ]
    

    sequence (map f xs) 经常出现以至于有一个名字:

    mapM f xs = sequence (map f xs)
    -- or, point-free style
    mapM f = sequence . map f
    

    所以你想要的功能只是

    allPropositions vs = mapM (\v -> [(v,True),(v,False)]) vs
    -- or, equivalently
    allPropositions = mapM (\v -> [(v,True),(v,False)])
    -- or, equivalently
    allPropositions = mapM $ \v -> [(v,True),(v,False)]
    -- or, equivalently, with -XTupleSections
    allPropositions = mapM $ \v -> map (v,) [True, False]
    

    【讨论】:

    • 这可能不是一个改进,但你也可以使用mapM (flip map [True, False] . (,))
    【解决方案2】:

    如果您不想要 monad 的全部功能,您仍然可以使用 sequenceA

    【讨论】:

      【解决方案3】:

      我会这样做:

      allPropositions :: [a] -> [[(a, Bool)]]
      allPropositions = foldr (\x xs -> (:) <$> [(x,True),(x,False)] <*> xs) [[]]
      

      你根本不需要单子的全部力量。你只需要applicative functors

      这是发生了什么:

      1. 对于基本情况,结果为[[]](即allPropositions [] = [[]])。
      2. 对于归纳情况,结果为⟦(:) [(x,True),(x,False)] xs⟧。请注意,双方括号(即⟦⟧)表示应用函子的上下文(在本例中为[])。

      虽然 rampion 的答案是正确的,但它使用了 sequencemapM 这两个函数。但是,正如我之前所说,在这种情况下,您不需要 monad 的全部功能。

      【讨论】:

        猜你喜欢
        • 2012-09-11
        • 2019-06-07
        • 2022-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-30
        • 1970-01-01
        相关资源
        最近更新 更多