I am trying to bend my head around list monads in haskell. I was trying to generate a list of all possible propositions given a list of strings designating boolean variables.
For instance calling :
mapM_ print $ allPropositions ["a","b"]
would yield the following result :
[("a",True),("b",True)]
[("a",True),("b",False)]
[("a",False),("b",True)]
[("a",False),("b",False)]
I have managed to do it using list comprehensions and recursion with the following code
allPropositions :: [String] -> [[(String,Bool)]]
allPropositions [] = [[]]
allPropositions (x:xs) = [(x,True):r | r <- allPropositions xs] ++ [(x,False):r | r <- allPropositions xs]
I was looking for a way to do it using the do notation similar to the following snippet but with a variable number of inputs. Is there a way to do it (nested monads,...) ?
allPropositions' = do
a <- [True, False]
b <- [True, False]
return([("a",a),("b",b)])
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] ]
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) ]
]
now you just need to pick one from each list to get your propositions holding a truth value for each variable:
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) comes up often enough that there's a name for it:
mapM f xs = sequence (map f xs)
-- or, point-free style
mapM f = sequence . map f
So your desired function is just
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]
This is how I would do it:
allPropositions :: [a] -> [[(a, Bool)]]
allPropositions = foldr (\x xs -> (:) <$> [(x,True),(x,False)] <*> xs) [[]]
You don't need the full power of monads at all. All you need are applicative functors.
Here's whats happening:
For the basis case the result is [[]] (i.e. allPropositions [] = [[]]).
For the inductive case the result is ⟦(:) [(x,True),(x,False)] xs⟧. Note that the double square brackets (i.e. ⟦⟧) denote the context of an applicative functor (in this case, []).
Although rampion's answer is correct, it makes use of sequence and mapM which are monadic functions. However, as I stated before you don't need the full power of monads in this case.
If you don't want the full power of monads, you can still use sequenceA.
Related
I'd like to take from these two lists to create a list of all combinations, where each combination is also a list.
E.g.
Given two lists: [1,2,3] and [True, False]
Combinations:
[(1, False), (2, False), (3, False)]
[(1, False), (2, False), (3, True )]
[(1, False), (2, True ), (3, False)]
[(1, True ), (2, False), (3, False)]
[(1, False), (2, True ), (3, True )]
[(1, True ), (2, False), (3, True )]
[(1, True ), (2, True ), (3, False)]
[(1, True ), (2, True ), (3, True )]
There should be 2^n combinations where n is the number of numbers.
EDIT:
Tried to do the following:
[(n, b) | n <- [1,2,3], b <- [True, False]]
(,) <$> [1,2,3] <*> [True, False]
We can avoid using length, which might be unsafe, since the list can have infinite length. By using recursion or a foldr pattern, we avoid that:
{-# LANGUAGE TupleSections #-}
allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = go
where go [] = [[]]
go (x:xs) = (:) <$> map (x,) vs <*> go xs
or with a foldr-pattern in a one-liner:
allComb :: [b] -> [a] -> [[(a,b)]]
allComb vs = foldr (\x -> ((:) <$> map (x,) vs <*>)) [[]]
For example:
Prelude> allComb [False, True] [1,2,3]
[[(1,False),(2,False),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,True),(3,True)],[(1,True),(2,False),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,True),(3,True)]]
The above approach will not work on infinite lists, although we can, given the first list contains at least one element, slightly alter the code, to generate the first element of the result: a list that zips all the elements in the second list with that item. I leave that as an exercise.
This can't be the most straightforward or most efficient answer.
But using the technique from How to generate a list of all possible strings from shortest to longest we can generate a list of all possible Boolean sequences. We take the ones that are the same length as the second list and then zip them with that list.
allBoolPermutations :: Int -> [[Bool]]
allBoolPermutations n = takeWhile (\l -> length l == n)
$ dropWhile (\l -> length l < n)
$ allBools
where
allBools = [ c : s | s <- []:allBools, c <- [True, False]]
zipWithBoolPermutations :: [a] -> [[(a, Bool)]]
zipWithBoolPermutations someList = map (zip someList)
(allBoolPermutations (length someList))
Then zipWithBoolPermutations [1,2,3] should give you what you want.
Your desired output can be produced by defining
foo :: [a] -> [b] -> [[(a, b)]]
foo nums bools =
map (zip nums) . sequence $ replicate (length nums) bools
=
let n = length nums
in
[ zip nums bs | bs <- sequence $ replicate n bools]
and calling
foo [1,2,3] [False, True]
That call is equivalent to
let nums = [1,2,3]
bools = [False, True]
n = 3
in
[ zip nums bs | bs <- sequence $ replicate n bools]
=
[ zip [1,2,3] bs | bs <- sequence $ replicate 3 [False, True]]
=
[ zip [1,2,3] (b:bs) | b <- [False, True]
, bs <- sequence $ replicate 2 [False, True]]
=
[ zip [1,2,3] (b:c:bs) | b <- [False, True]
, c <- [False, True]
, bs <- sequence $ replicate 1 [False, True]]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- sequence $ replicate 0 [False, True] ]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- sequence [] ]
=
[ zip [1,2,3] (b:c:d:bs) | b <- [False, True]
, c <- [False, True]
, d <- [False, True]
, bs <- [[]] ]
=
[ zip [1,2,3] (b:c:d:[]) | b <- [False, True]
, c <- [False, True]
, d <- [False, True] ]
i.e.
[ zip [1,2,3] [b,c,d] | b <- [False, True]
, c <- [False, True]
, d <- [False, True] ]
and if evaluate this last expression, we also get the same result.
Filling up the three spaces with each possible combination of the two available values is like having all possible functions from 3 spaces to 2 values, whatever those spaces and values are.
Mathematicians write this function as 23, and indeed, we get 2^3 = 8 outputs.
edit: the sequence ... replicate combo is actually just reimplementing another built-in, replicateM:
foo ns bs = map (zip ns) (replicateM (length ns) bs)
because replicateM n a is just like sequence (replicate n a), but without actually building the intermediate list.
For the pointfree aficionados, we can thus have
foo ns = map (zip ns) . replicateM (length ns)
= (.) ((map . zip) ns) ((replicateM . length) ns)
= ((.) . map . zip <*> replicateM . length) ns
i.e.
foo = (.) . map . zip <*> replicateM . length
Nice and short:
traverse ((<$> [True, False]) . (,)) [1,2,3]
Or less pointfree, but perhaps more understandable:
traverse (\x -> [(x,True), (x,False)]) [1,2,3]
The inner function ((<$> [True, False]) . (,) or \x -> [(x,True), (x,False)]) takes each element such as 1 and turns it into [(1,True),(1,False)]. If you think of traverse f as being sequence . fmap f, then the fmap f part means do that function to each thing in the list (yielding [[(1,True),(1,False)],[(2,True),(2,False)],[(3,True),(3,False)]]), and the sequence part means combine them with the List applicative (which models non-determinism) to create all possible combinations (yielding [[(1,True),(2,True),(3,True)],[(1,True),(2,True),(3,False)],[(1,True),(2,False),(3,True)],[(1,True),(2,False),(3,False)],[(1,False),(2,True),(3,True)],[(1,False),(2,True),(3,False)],[(1,False),(2,False),(3,True)],[(1,False),(2,False),(3,False)]]).
Let's say I have the following input:
[(0, [1, 2]) , (2, [3, 4]) , (4, [])
This is an adjacency list and I want to convert it as such:
[(0,1), (0,2), (2,3), (2, 4)] -- notice how there is no 4 mapping to anything
Here is what I have so far:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv adj = map fn adj -- mapping (0, [1, 2]) should give me [(0, 1), (0, 2)]
fn:: (Int, [Int]) -> [(Int, Int)]
fn (rt, list) = -- somehow perform [(rt, l[0]), (rt, l[1]) ...]
List comprehension can do the trick:
conv :: [(a, [b])] -> [(a, b)]
conv xys = [(x, y) | (x, ys) <- xys, y <- ys ]
Or we can use concatMap here:
conv :: Foldable f => f (a, [b]) -> [(a, b)]
conv = concatMap (uncurry (map . (,)))
Here the inner function uncurry (map . (,)) takes a tuple (x, ys) and thus performs a map (x,): the uncurry basically unpacks the tuple (x, ys), and calls (map . (,)) x ys, so that means that we obtain (map (x,)) ys. The above syntax uses the TupleSections extension, but we do not need to activate that extension in the real program, since we never write such syntax. Your fn function you defined is thus equivalent to uncurry (map . (,)).
We thus use this function in a concatMap that will pass the 2-tuples, and concatenate the lists these individual tuples create.
or we can use the "bind" >>= :: Monad m => m a -> (a -> m b) -> m b function:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (\(x, ys) -> ys >>= return . (x,))
or shorter:
conv :: Monad m => m (a, m b) -> m (a, b)
conv = (=<<) (uncurry (fmap . (,)))
the nice thing about the latter is that it also works with Maybes, etc. For example:
Prelude> conv [(0, [1, 2]) , (2, [3, 4]) , (4, [])]
[(0,1),(0,2),(2,3),(2,4)]
Prelude> conv Nothing
Nothing
Prelude> conv (Just (3, Nothing))
Nothing
Prelude> conv (Just (3, Just 2))
Just (3,2)
Taking advantage of instance Traversable ((,) a), we have this remarkably short (and remarkably inscrutable) solution:
conv :: [(Int, [Int])] -> [(Int, Int)]
conv = (sequence =<<)
The most general type of (sequence =<<) is (Monad m, Traversable t) => m (t (m a)) -> m (t a).
Good day everyone.
What I am trying to accomplish is to convert a list like
[ [1, 2, 3], [25, 24, 23, 22], [13] ] into [ [1], [2], [3], [25], [24], [23], [22], [13] ].
I tried something like
reWrap :: [[a]] -> [[a]]
reWrap data = map (map (:[])) data
but of course it just wrapped the contents even deeper into brackets. I'm new into functional programming so any help or tip would be much appreciated. Thank you in advance!
This is clearly a case for good old list comprehension:
rewrap xss = [ [x] | xs <- xss, x <- xs ]
This is quite easy, if you use the concatMap prelude function:
λ> :t concatMap
concatMap :: (a -> [b]) -> [a] -> [b]
What concatMap does is map a function, then concat the resulting lists.
If we use this definition, we can get the desired effect:
solution :: [[a]] -> [[a]]
solution = concatMap (map (:[]))
Here it is in action:
λ> solution [[1,2,3],[4,5,6]]
[[1],[2],[3],[4],[5],[6]]
λ> solution [[1,2,3],[],[12,19]]
[[1],[2],[3],[12],[19]]
As #amalloy said, the >>= function in the case of lists is equivalent to flip concatMap, so you could say this:
solution = (=<<) (map (:[]))
first you need to concat the list
this [ [1, 2, 3], [25, 24, 23, 22], [13] ]
becomes [1,2,3,25,24,23,22,13]
then you need to wrap each element in a list
reWrap = map (:[]) . concat
Perhaps reWrap = (>>= map return)? But this is probably too abstruse for a beginner. There is a solution very close to the one you were trying: rewrap xs = concat $ map (map (:[])) xs. Note that your output was very close to what you wanted, except that everything was exactly one level too deep in a list; concat takes a list of lists and flattens it.
My solution is really doing the same thing, just with more shorthand. Specifically, (:[]) is just return specialized to lists, and concat $ map f xs is the same as xs >>= f for lists. Then I also removed the explicit xs argument, since all you do with it is pass it to the partially-applied function you're really defining.
A recursive version, not the shortest, yet that illustrates the wrapping of each item in each nested list, and that concatenates wrapped nested lists,
reWrap :: [[a]] -> [[a]]
reWrap [] = [[]]
reWrap (xs:xss) = (map (:[]) xs) ++ reWrap xss
I have the following function
combinations :: [[a]] -> [[a]]
combinations [] = [[]]
combinations (xs:xss) = concat [map (x:) yss | x <- xs]
where yss = combinations xss
Which produces all combinations between its elements:
*Main> combinations [[1,2],[2,3,4],[5,6]]
[[1,2,5],[1,2,6],[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,2,5],[2,2,6],[2,3,5],[2,3,6]
,[2,4,5],[2,4,6]]
I some how feel there must be a monadic way to do this
foobar = do
n <- [1,2]
ch <- [3,4,5]
return[n,ch]
This is how far I came. But I am stuck.
Your function is sequence for the list monad.
> :t sequence
sequence :: Monad m => [m a] -> m [a]
> sequence [[1,2],[2,3,4],[5,6]]
[[1,2,5],[1,2,6],[1,3,5],[1,3,6],[1,4,5],[1,4,6],[2,2,5],[2,2,6],[2,3,5],[2,3,6],
[2,4,5],[2,4,6]]
The best I've been able to come up with is
combinations [] = [[]]
combinations (xs:xss) = do
x <- xs
ys <- combinations xss
return $ x : ys
The way I derived this was I first converted the list comprehension into monadic code (which also meant dropping the concat to get it to type check)
combinations (xs:xss) =
let yss = combinations xss
in do
x <- xs
map (x:) yss
Then I realized that map (x:) yss is exactly fmap (x:) yss, which is exactly yss >>= return . (x:), so I knew I could do
combinations (xs:xss) =
let yss = combinations xss
in do
x <- xs
ys <- yss
return $ x : ys
And then it can be inlined as
combinations (xs:xss) = do
x <- xs
ys <- combinations xss
return $ x : ys
I have a list of tuples that look like this.
[ [(1,True),(2,True)] , [(3,False),(4,False),(5,False)] ]
My goal is so get [1,2,3,4,5] of out that mess.
I tried to use map and filter to remove all the Bools but filter also removed the first element in the tuple. If I can remove the Bools in each tuple then I can maybe use a loop to assign fst of each tuple to a new empty list?
f :: [[(a, b)]] -> [a]
f = concatMap (map fst)
Then f [ [(1,True),(2,True)] , [(3,False),(4,False),(5,False)] ] is [1,2,3,4,5].
Or with list comprehensions:
f xss = [fst x | xs <- xss, x <- xs]
Try this (edited, thanks to Michael Kohl's and pat's comments):
fun :: [[(a,b)]] -> [a]
fun = map fst . concat
Then in GHC:
*Main> let l = [ [(1,True),(2,True)] , [(3,False),(4,False),(5,False)] ]
[[(1,True),(2,True)],[(3,False),(4,False),(5,False)]]
*Main> fun l
[1,2,3,4,5]
foldl1 (\acc x -> acc ++ x) [a | b <- lst, let a = map fst b]