簡體   English   中英

在 Haskell 中生成一組布爾變量的所有組合

[英]Generating all the combinations of a set of boolean variables in Haskell

我正試圖在 haskell 中繞過列表 monad。 給定指定布爾變量的字符串列表,我試圖生成所有可能命題的列表。

例如調用:

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]

我正在尋找一種方法來使用類似於以下代碼段的 do 表示法,但具有可變數量的輸入。 有沒有辦法做到這一點(嵌套單子,...)?

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

你需要的是sequence :: Monad m => [ma] -> 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]

這就是我將如何做到的:

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

您根本不需要 monad 的全部功能。 你所需要的只是applicative functors

這是發生了什么:

  1. 對於基本情況,結果是[[]] (即allPropositions [] = [[]] )。
  2. 對於歸納的情況,結果是⟦(:) [(x,True),(x,False)] xs⟧ 請注意,雙方括號(即⟦⟧ )表示應用函子的上下文(在本例中為[] )。

盡管rampion 的答案是正確的,但它使用了作為單子函數的sequencemapM 但是,正如我之前所說,在這種情況下您不需要 monad 的全部功能。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM