我试图在haskell的名单monads周围弯曲。我试图在给出一个指定布尔变量的字符串列表的情况下生成所有可能命题的列表。
例如致电:
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]
我一直在寻找一种方法来使用类似于以下代码段的符号,但具有可变数量的输入。有办法吗(嵌套monad,...)?
allPropositions' = do
a <- [True, False]
b <- [True, False]
return([("a",a),("b",b)])
答案 0 :(得分:4)
您需要的是sequence :: Monad m => [m a] -> m [a]
。
特别是,对于[]
monad,sequence
会获取n
列表的列表,并生成所有n
长度列表,从每个列表中绘制一个元素。
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]
答案 1 :(得分:1)
我就是这样做的:
allPropositions :: [a] -> [[(a, Bool)]]
allPropositions = foldr (\x xs -> (:) <$> [(x,True),(x,False)] <*> xs) [[]]
你根本不需要monad的全部力量。您所需要的只是applicative functors。
以下是发生的事情:
[[]]
(即allPropositions [] = [[]]
)。⟦(:) [(x,True),(x,False)] xs⟧
。请注意,双方括号(即⟦⟧
)表示应用仿函数的上下文(在本例中为[]
)。虽然rampion的答案是正确的,但它使用了sequence
和mapM
这些是monadic函数。但是,正如我之前所说,在这种情况下你不需要monad的全部功能。
答案 2 :(得分:1)
如果您不希望使用monad的全部功能,仍然可以使用sequenceA
。