I was playing around with >>= today, trying to understand monads, and found an interesting pattern. When working with the list monad, >>= seemed to behave like concatMap. I searched around to try to find any similarity, looking specifically in the definitions on hackage.
Some things I tried:
[1, 2, 3] >>= (iter 5 id) => [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]
concatMap (iter 5 id) [1, 2, 3]=> [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]
[1, 2, 3] >>= (iter 5 (+5)) => [1,6,11,16,21,2,7,12,17,22,3,8,13,18,23]
concatMap (iter 5 (+5) ) [1, 2, 3] => [1,6,11,16,21,2,7,12,17,22,3,8,13,18,23]
iter is just non-infinite iterate,
iter i f a = toL $ Data.Sequence.iterateN i f a
where
toL = Data.Foldable.toList :: Data.Sequence.Seq a -> [a]
(working in repl.it so the imports are screwed up).
Is (>>=) equivalent to concatMap for lists?
Is it the generalization of concatMap?
Yes, with the arguments flipped. Comparing these type signatures should bring out the similarity, though the special list syntax interferes:
Prelude> :t flip concatMap
flip concatMap :: Foldable t => t a -> (a -> [b]) -> [b]
Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
Yes, (=<<) is concatMap for lists. >>= is just a combination of fmap and join (the generalization of concat) for any Monad, so this makes intuitive sense as well.
Related
I'm currently preparing for my final exam regarding Haskell, and I am going over the Monads and we were giving an example such as:
Given the following definition for the List Monad:
instance Monad [] where
m >>= f = concatMap f m
return x = [x]
where the types of (>>=) and concatMap are
(>>=) :: [a] -> (a -> [b]) -> [b]
concatMap :: (a -> [b]) -> [a] -> [b]
What is the result of the expression?
> [1,2,3] >>= \x -> [x..3] >>= \y -> return x
[1, 1, 1, 2, 2, 3] //Answer
Here the answer is different from what I thought it to be, now we briefly went over Monads, but from what I understand (>>=) is called bind and could be read in the expression above as "applyMaybe". In this case for the first part of bind we get [1,2,3,2,3,3] and we continue to the second part of the bind, but return x is defined to return the list of x. Which should have been [1,2,3,2,3,3]. However, I might have misunderstood the expression. Can anyone explain the wrong doing of my approach and how should I have tackled this. Thanks.
this case for the first part of bind we get [1,2,3,2,3,3]
Correct.
and we continue to the second part of the bind, but "return x" is defined to return the list of x. Which should have been [1,2,3,2,3,3].
Note that, in...
[1,2,3] >>= \x -> [x..3] >>= \y -> return x
... x is bound by (the lambda of) the first (>>=), and not by the second one. Some extra parentheses might make that clearer:
[1,2,3] >>= (\x -> [x..3] >>= (\y -> return x))
In \y -> return x, the values bound to y (that is, the elements of [1,2,3,2,3,3]) are ignored, and replaced by the corresponding values bound to x (that is, the elements of the original list from which each y was generated). Schematically, we have:
[1, 2, 3] -- [1,2,3]
[1,2,3, 2,3, 3] -- [1,2,3] >>= \x -> [x..3]
[1,1,1, 2,2, 3] -- [1,2,3] >>= \x -> [x..3] >>= \y -> return x
First, let's be clear how this expression is parsed: lambdas are syntactic heralds, i.e. they grab as much as they can to their right, using it as the function result. So what you have there is parsed as
[1,2,3] >>= (\x -> ([x..3] >>= \y -> return x))
The inner expression is actually written more complicated than it should be. y isn't used at all, and a >>= \_ -> p can just be written as a >> p. There's an even better replacement though: generally, the monadic bind a >>= \q -> return (f q) is equivalent to fmap f a, so your expression should really be written
[1,2,3] >>= (\x -> (fmap (const x) [x..3]))
or
[1,2,3] >>= \x -> map (const x) [x..3]
or
[1,2,3] >>= \x -> replicate (3-x+1) x
At this point it should be pretty clear what the result will be, since >>= in the list monad simply maps over each element and concatenates the results.
I want a function that takes in a list of Maybe a, and returns Just [a] if all contents are Just a, otherwise returns Nothing.
f :: [Maybe a] -> Maybe [a]
-- f [Just x, Just y ] = Just [x, y]
-- f [Just x, Nothing] = Nothing
I think it doesn't have to be Maybe and List but any Functor Applicative or Monad, but I can't think up the way.
This is a great example of where hoogle comes in handy. It's a search engine where you can enter a type signature and get the functions that match—even if they are more polymorphic.
Entering [Maybe a] -> Maybe [a] we get a bunch of results.
The first one is:
sequence :: Monad m => [m a] -> m [a]
We can try this out in GHCi:
Prelude> let xs = [Just 1, Just 2, Just 3]
Prelude> sequence xs
Just [1,2,3]
Prelude> let xs = [Just 1, Nothing, Just 3]
Prelude> sequence xs
Nothing
Hey, look at that: exactly what we were looking for! So the function you want is sequence which also happens to work for types other than Maybe.
This is working
unique :: (a -> Bool) -> [a] -> Bool
unique p xs = 1 == length (filter p xs)
But now I want it in the form:
unique = (== 1) . length . filter
Error message:
Couldn't match expected type `[a] -> Bool' with actual type `Bool'
Expected type: b0 -> [a] -> Bool
Actual type: b0 -> Bool
In the first argument of `(.)', namely `(== 1)'
In the expression: (== 1) . length . filter
Why is this not working?
This is because filter is a two argument function. You can get around this using the handy operator
(.:) = (c -> d) -> (a -> b -> c) -> a -> b -> d
(.:) = (.) . (.)
-- Important to make it the same precedence as (.)
infixr 9 .:
unique = ((== 1) . length) .: filter
If you look at the type of (length .) in GHCi, you'll get
(length .) :: (a -> [b]) -> a -> Int
This means that it takes a single argument function that returns a list. If we look at the type of filter:
filter :: (a -> Bool) -> [a] -> [a]
This can be rewritten to make it "single argument" as
filter :: (a -> Bool) -> ([a] -> [a])
And this quite clearly does not line up with a -> [b]! In particular, the compiler can't figure out how to make ([a] -> [a]) be the same as [b], since one is a function on lists, and the other is simply a list. So this is the source of the type error.
Interestingly, the .: operator can be generalized to work on functors instead:
(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
(.:) = fmap fmap fmap
-- Since the first `fmap` is for the (->) r functor, you can also write this
-- as (.:) = fmap `fmap` fmap === fmap . fmap
What is this good for? Say you have a Maybe [[Int]], and you wanted the sum of each sublist inside the Just, provided it exists:
> let myData = Just [[3, 2, 1], [4], [5, 6]]
> sum .: myData
Just [6, 4, 11]
> length .: myData
Just [3, 1, 2]
> sort .: myData
Just [[1,2,3],[4],[5,6]]
Or what if you had a [Maybe Int], and you wanted to increment each one:
> let myData = [Just 1, Nothing, Just 3]
> (+1) .: myData
[Just 2,Nothing,Just 4]
The possibilities go on and on. Basically, it lets you map a function inside two nested functors, and this sort of structure crops up pretty often. If you've ever had a list inside a Maybe, or tuples inside a list, or IO returning a string, or anything like that, you've come across a situation where you could use (.:) = fmap fmap fmap.
This is a trival question.
But what is the standard way to map a function (+1 in this example) on nested list?
map (\x -> map (+1) x) [[1,2,3],[4,5,6]]
I use the above way in my code, but what is a good way to do that? Is there something like a mapNested (+1) [[1,2,3],[4,5,6]] or similar? I used google and hoogle but got too much generic results.
There's a few ways but the most obvious is:
Prelude> map (map (+1)) [[1,2,3],[4,5,6]]
[[2,3,4],[5,6,7]]
This would be the textbook answer.
Maybe you like to do the outer part with a list comprehension?
Prelude> [ map (+1) xs | xs <- [[1,2,3],[4,5,6]] ]
[[2,3,4],[5,6,7]]
Or even the whole thing?
Prelude> [ [ x + 1 | x <- xs ] | xs <- [[1,2,3],[4,5,6]] ]
[[2,3,4],[5,6,7]]
I don't think it defined anywhere in the standard library, but you can define it as such:
mapNested :: (a -> b) -> [[a]] -> [[b]]
mapNested = map . map
Or to make it more generic (ie. work on other functors than lists):
fmapNested :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
fmapNested = fmap . fmap
Example use:
fmapNested (+1) [Some 1, None, Some 3] -- == [Some 2, None, Some 4]
You need composition of maps: (map . map) (+1) [[1,2,3],[4,5,6]]
i am looking for a function which takes a function (a -> a -> a) and a list of [Maybe a] and returns Maybe a. Hoogle gave me nothing useful. This looks like a pretty common pattern, so i am asking if there is a best practice for this case?
>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing
Thanks in advance, Chris
You should first turn the [Maybe a] into a Maybe [a] with all the Just elements (yielding Nothing if any of them are Nothing).
This can be done using sequence, using Maybe's Monad instance:
GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing
The definition of sequence is equivalent to the following:
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return (x:xs)
So we can expand the latter example as:
do x <- Just 1
xs <- do
y <- Just 2
ys <- do
z <- Nothing
zs <- return []
return (z:zs)
return (y:ys)
return (x:xs)
Using the do-notation expression of the monad laws, we can rewrite this as follows:
do x <- Just 1
y <- Just 2
z <- Nothing
return [x, y, z]
If you know how the Maybe monad works, you should now understand how sequence works to achieve the desired behaviour. :)
You can then compose this with foldr using (<$>) (from Control.Applicative; equivalently, fmap or liftM) to fold your binary function over the list:
GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3
Of course, you can use any fold you want, such as foldr, foldl1 etc.
As an extra, if you want the result to be Nothing when the list is empty, and thus be able to omit the zero value of the fold without worrying about errors on empty lists, then you can use this fold function:
mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs
and similarly for foldr, foldl, etc. You'll need to import Control.Monad for this.
However, this has to be used slightly differently:
GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3
or
GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3
This is because, unlike the other folds, the result type looks like m a instead of a; it's a bind rather than a map.
As I understand it, you want to get the sum of a bunch of maybes or Nothing if any of them are Nothing. This is actually pretty simple:
maybeSum = foldl1 (liftM2 (+))
You can generalize this to something like:
f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2
When used with the Maybe monad, f works exactly the way you want.
If you care about empty lists, you can use this version:
f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ [] = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
What about something as simple as:
λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing
Or, by using (+):
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing
So, maybeSum = fmap sum . sequence.