Related
I'd like to make the nested applicative functors of different types. For example, nested simple functors of different types (in ghci) work fine:
Prelude> ((+2) <$>) <$> (Just [1..4])
Just [3,4,5,6]
But for applicative functors of different types:
Prelude> ((*) <$>) <$> (Just [1,2,3]) <*> (Just [4,5,6,7])
<interactive>:56:1: error:
* Couldn't match type `[Integer -> Integer]' with `[Integer] -> b'
isn't working! I want to obtain something like this:
Just [4,5,6,7,8,10,12,14,12,15,18,21]
I know that applicative functors have intermediate position between functors and monads. And I can see this exercise as preliminary before topic about monad transformers.
Besides nesting lifts and fmaps, another option to compose applicative functors is the Data.Functor.Compose newtype:
newtype Compose f g a = Compose { getCompose :: f (g a) }
for example:
ghci> let Compose result = (*) <$> Compose (Just [1,2,3]) <*> Compose (Just [4,5,6,7])
ghci> result
Just [4,5,6,7,8,10,12,14,12,15,18,21]
Applicatives are so well-behaved that a single newtype suffices to compose any two types that are instances. And there are other ways to combine them besides nesting, like Product and Day convolution:
data Product f g a = Pair (f a) (g a)
data Day f g a = forall b c. Day (f b) (g c) (b -> c -> a)
Monads do not compose as well though, so we need a different newtype for each monad in order to augment some other monad with the first monad's abilities. We call those newtypes monad transformers.
In this case, you want:
liftA2 (*) <$> Just [1, 2, 3] <*> Just [4, 5, 6, 7]
Or:
liftA2 (liftA2 (*)) (Just [1, 2, 3]) (Just [4, 5, 6, 7])
The outer … <$> … <*> … or liftA2 operates on Maybe, while the inner one operates on []. If you didn’t know this, you could figure it out by asking GHCi for the type of what you should put there, for example with a typed hole:
:t _ <$> (Just [1 :: Int, 2, 3]) <*> (Just [4 :: Int, 5, 6, 7]) :: Maybe [Int]
It gives back:
_ :: [Int] -> [Int] -> [Int]
And the behaviour you want for combining the lists is \ xs ys -> (*) <$> xs <*> ys, which can be abbreviated liftA2 (*). ((*) <$>) or fmap (*) didn’t work because that’s only half of what you need: it operates on a single list (using Functor), while you want to combine two (using Applicative).
Of course, liftA2 (liftA2 (*)) works on any two nested applicative functors whose elements are numeric:
(Applicative f, Applicative g, Num a)
=> f (g a) -> f (g a) -> f (g a)
For example, nested lists:
liftA2 (liftA2 (*)) [[1], [2], [3]] [[4, 5, 6]]
== [[4,5,6],[8,10,12],[12,15,18]]
-- (Transposing the inputs transposes the output.)
liftA2 (liftA2 (*)) [[1, 2, 3]] [[4], [5], [6]]
== [[4,8,12],[5,10,15],[6,12,18]]
Or lists of Maybe:
liftA2 (liftA2 (*)) [Just 1, Nothing, Just 3] [Just 4, Nothing, Just 6]
== [Just 4, Nothing, Just 6,
Nothing, Nothing, Nothing,
Just 12, Nothing, Just 18]
Or even something more exotic, like lists of functions:
($ (3, 5)) <$> (liftA2 (+) <$> [fst, snd] <*> [snd, fst])
== [fst (3, 5) + snd (3, 5),
fst (3, 5) + fst (3, 5),
snd (3, 5) + snd (3, 5),
snd (3, 5) + fst (3, 5)]
== [3+5, 3+3, 5+5, 5+3]
== [8,6,10,8]
We may also do this quite stragithforward with prelude functions. Your first part is nice though.
((*) <$>) <$> (Just [1,2,3]) with type Num a => Maybe [a -> a]
All we need is to fmap the applicative list in Maybe monad to a list in Maybe monad. So one approach could be to bind the first part to (<$> Just [4, 5, 6, 7]) . (<*>) :: Num a => [a -> b] -> Maybe [b]
((*) <$>) <$> (Just [1,2,3]) >>= (<$> Just [4,5,6,7]) . (<*>)
yields to
Just [(1*),(2*),(3*)] >>= (<$> Just [4,5,6,7]) . (<*>)
yields to
([(1*),(2*),(3*)] <*>) <$> Just [4,5,6,7]
yields to
Just [4,5,6,7,8,10,12,14,12,15,18,21]
bit confused. fmap sounds like it can map all over a list of Maybe's, but I can't get it to work if I use e.g. fApplyFunctor = (+1) <$> [Just 1, Just 2].
What seems to work perfectly fine is: map ((+1) <$>) [Just 1, Just 2, Just 3]. This seems to be overkill in that sense that I recall fmap could do that by itself already...
No fmap means you can map over an arbitrary Functor type (well think about it for now as a collection), but you only do this one "functor level" deep. In case you fmap with a list, it is exactly equivalent to map.
fmap however is defined over all sorts of Functors, like lists, Maybes, etc. Here you can thus fmap in the fmap to map over two levels:
fApplyFunctor = fmap (fmap (+1)) [Just 1, Just 2]
This will then result in:
Prelude> fmap (fmap (+1)) [Just 1, Just 2]
[Just 2,Just 3]
Prelude> (fmap (+1)) <$> [Just 1, Just 2]
[Just 2,Just 3]
Prelude> ((+1) <$>) <$> [Just 1, Just 2]
[Just 2,Just 3]
EDIT: like #DanielWagner says, there exists a data type Compose which works over two (or more if you cascade) Functors and thus allows us to fmap two levels deep. This is implemented like:
newtype Compose f g a = Compose { getCompose :: f (g a) }
instance (Functor f, Functor g) => Functor (Compose f g) where
fmap f (Compose x) = Compose (fmap (fmap f) x)
so here we again perform an fmap on two levels:
Prelude Data.Functor.Compose> getCompose ((+1) <$> Compose [Just 1, Just 2])
[Just 2,Just 3]
But as you see it requires some syntax to first wrap the data in a Compose, and then to later "unwrap" it out of the Compose, so this requires some extra work as well.
Is there a more idiomatic way to implement the following? I feel like I'm missing a way to get rid of the lambda, but couldn't figure out a way to convert it to point-free. Maybe there is another non-applicative way as well that is more straight forward?
import Data.Maybe
import Control.Applicative
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4]
-- Just 7
foldl (\x y -> pure (+) <*> x <*> y) (Just 0) [Just 3, Just 4, Nothing]
-- Nothing
I'd just use sequence from Control.Monad:
> fmap sum $ sequence [Just 3, Just 4]
Just 7
> fmap sum $ sequence [Just 3, Just 4, Nothing]
Nothing
For the point-free form:
sumMaybe :: Num a => [Maybe a] -> Maybe a
sumMaybe = fmap sum . sequence
The most direct way to eliminate the lambda is to use liftA2; it's exactly the code you wrote
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = pure f <*> x <*> y
foldl (liftA2 (+)) (Just 0) [Just 1, Just 2]
then we have a few choices for how to propagate the errors. This code has it that any Nothing will lead to a total failure. We can do that in two steps like #bhekilr suggested using sequence.
sum <$> sequence [Just 1, Just 2] sum <$> sequence [Just 1, Nothing]
Just (sum [1,2]) sum <$> Nothing
Just 3 Nothing
We can also use the fact that (+) induces a Monoid on the values in order to just "ignore" Nothings. Most literally that would be
import Data.Monoid
getSum $ foldMap (maybe mempty Sum) [Just 1, Just 2, Nothing]
-- equivalent to, but faster than
getSum . mconcat . map (maybe mempty Sum) $ [Just 1, Just 2, Nothing]
getSum . mconcat $ [Sum 1, Sum 2, Sum 0]
3
But we can also use catMaybe from Data.Monoid to do it in two steps
sum . catMaybes $ [Just 1, Just 2, Nothing]
sum [1, 2]
3
I think foldM works well here.
import Control.Monad
sumMay = foldM (fmap . (+)) 0
I think it's the clearest as it maps (Ba duh duh ching) to what you'd do in pure code.
You can lift the (+) in the Maybe Monad with:
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2]
Just 3
input> fold (liftM2 (+)) (Just 0) [Just 1, Just 2, Nothing]
Nothing
import Data.Maybe
import Data.List
sumMaybes = sum . catMaybes
I am relatively new to Haskell so apologies if my question sounds stupid. I have been trying to understand how function composition works and I have come across a problem that I was wondering someone could help me with. I am using map in a function composition in the following two scenarios:
map (*2) . filter even [1,2,3,4]
map (*2) . zipWith max [1,2] [4,5]
Although both the filter and zipWith functions return a list, only the first composition works while the second composition throws the below error:
"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]'
Any suggestions would be greatly appreciated.
Recall the type of (.).
(.) :: (b -> c) -> (a -> b) -> a -> c
It takes three arguments: two functions and an initial value, and returns the result of the two functions composed.
Now, application of a function to its arguments binds tighter than the (.) operator.
So your expression:
map (*2) . filter even [1,2,3,4]
is parsed as:
(.) (map (*2)) (filter even [1,2,3,4])
now, the first argument, map (*2) is ok. It has type (b -> c), where b and c is Num a => [a]. However, the second argument is a single list:
Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral a => [a]
and so the type checker will complain that you're passing a [a] as an argument when the (.) function needs a function.
And that's what we see:
Couldn't match expected type `a0 -> [b0]' with actual type `[a1]'
In the return type of a call of `filter'
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]'
In the expression: map (* 2) . filter even [1, 2, 3, 4]
So... parenthesization!
Either use the $ operator to add a parenthesis:
map (*2) . filter even $ [1,2,3,4]
or use explicit parens, removing the composition of two functions
map (*2) (filter even [1,2,3,4])
or even:
(map (*2) . filter even) [1,2,3,4]
The following forms are valid:
map (* 2) $ filter even [1, 2, 3, 4]
(map (* 2) . filter even) [1, 2, 3, 4]
map (* 2) $ zipWith max [1, 2] [4, 5]
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5]
but not the following:
map (* 2) . filter even [1, 2, 3, 4]
map (* 2) . zipWith max [1, 2] [4, 5]
(map (* 2) . zipWith max) [1, 2] [4, 5]
Why is that so? Well, take for example
map (* 2) . zipWith max [1, 2] [4, 5]
it is the same as
(map (* 2)) . (((zipWith max) [1, 2]) [4, 5])
(map (* 2)) has type [Int] -> [Int] (assuming defaulting for Int), (((zipWith max) [1, 2]) [4, 5]) has type [Int] and (.) has type (b -> c) -> (a -> b) -> a -> c or ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int] in this non-polymorphic case, so this is ill-typed. On the other hand ($) has type (a -> b) -> a -> b, or ([Int] -> [Int]) -> [Int] -> [Int] in this non-polymorphic case, so this:
(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5])
is well-typed.
The result of zipWith max [1,2] [4,5] is a list, not a function. The (.) operator requires a function as its right operand. Hence the error on your second line. Probably what you want is
map (*2) (zipWith max [1,2] [4,5])
Your first example does not compile on WinHugs (Hugs mode); it has the same error. The following will work
(map (*2) . filter even) [1,2,3,4]
as it composes two functions and applies the resulting function to an argument.
Due to the low precedence of (.), Haskell parses
map (*2) . filter even [1,2,3,4]
as
map (*2) . (filter even [1,2,3,4])
i.e. compose map (*2) (a function) with the result of filter even [1,2,3,4] (a list), which makes no sense, and is a type error.
You can fix this using #Theodore's suggestions, or by using ($):
map (*2) . filter even $ [1,2,3,4]
If you check the type of map it is: (a -> b) -> [a] -> [b]
So, it takes a function of a into b and then a list of a and returns a list of b. Right?
Now, you already provide a function of a into b by passing the parameter (*2). So, your partially applied map function end up being: [Integer] -> [Integer] meaning that you will receive a list of integers and return a list of integers.
Up to this point, you could compose (.) a function that has the same signature. If you check what is the type of filter even you would see that it is: [Integer] -> [Integer], as such a valid candidate for composition here.
This composition then, does not alter the final signature of the function, if you check the type of: map (*2) . filter even it is [Integer] -> [Integer]
This would not be the case of the map (*2) . zipWith max [1,2] [4,5] because the zipWith max does not have the same signature as the one expected by map (*2).
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.