在Haskell中生成一组布尔变量的所有组合

Gae*_*ael 6 monads haskell list-comprehension list

我试图在haskell的名单monads周围弯曲.我试图在给出一个指定布尔变量的字符串列表的情况下生成所有可能命题的列表.

比如说:

mapM_ print $ allPropositions ["a","b"]
Run Code Online (Sandbox Code Playgroud)

会产生以下结果:

[("a",True),("b",True)]
[("a",True),("b",False)]
[("a",False),("b",True)]
[("a",False),("b",False)]
Run Code Online (Sandbox Code Playgroud)

我已经设法使用列表推导和递归使用以下代码

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

我正在寻找一种方法来使用类似于以下代码段的符号,但具有可变数量的输入.有办法吗(嵌套monad,...)?

allPropositions' = do
    a <- [True, False]
    b <- [True, False]
    return([("a",a),("b",b)])
Run Code Online (Sandbox Code Playgroud)

ram*_*ion 4

What you need is sequence :: Monad m => [m a] -> m [a].

In particular, for the [] monad, sequence takes a list of n lists, and produces all n-length lists drawing one element from each list at a time.

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] ]
Run Code Online (Sandbox Code Playgroud)

This helps in your particular case because if you have a list of n strings, you can produce the possibilities for each string easily:

map (\s -> [(s,True), (s,False)] ["a", "b", "c"] = 
   [ [("a", True), ("a", False) ]
   , [("b", True), ("b", False) ]
   , [("c", True), ("c", False) ]
   ]
Run Code Online (Sandbox Code Playgroud)

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

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)]
   ]
Run Code Online (Sandbox Code Playgroud)

sequence (map f xs)这个词经常出现,所以有一个名字:

mapM f xs = sequence (map f xs)
-- or, point-free style
mapM f = sequence . map f
Run Code Online (Sandbox Code Playgroud)

所以你想要的功能就是

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]
Run Code Online (Sandbox Code Playgroud)