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.
Related
I was trying to understand applicative and how i can use it as a cartesian product between K functions and N parameters ,and i can't comprehend why i can't do the following:
[Just (+1),Just (+2)] <*> [Just 1 ,Just 2] renders
Error
* Couldn't match expected type `Maybe Integer -> b'
with actual type `Maybe (Integer -> Integer)'
* Possible cause: `Just' is applied to too many arguments In the expression: Just (+ 1) In the first argument of `(<*>)', namely `[Just (+ 1), Just (+ 2)]'
In the expression: [Just (+ 1), Just (+ 2)] <*> [Just 1, Just 2]
I do not understand since from the definition it is supposed to take the functions out of the context, take the values and apply all combinations.
I have also tried :
:t [pure (+1),pure (+2)] <*> [Just 1 ,Just 2] :: Num a => [a -> a] and i can't understand why the resulting type is not a list of values (and not a->a) ,since all operators expect only one argument,and i am already supplying that.
Can someone shed some light?
There are two applicative layers involved here ([] and Maybe), so (<*>) itself must be applied applicatively:
GHCi> (<*>) <$> [Just (+1),Just (+2)] <*> [Just 1 ,Just 2]
[Just 2,Just 3,Just 3,Just 4]
This use case is captured by the Compose newtype. Nesting any two applicative functors gives rise to another applicative:
GHCi> import Data.Functor.Compose
GHCi> Compose [Just (+1),Just (+2)] <*> Compose [Just 1 ,Just 2]
Compose [Just 2,Just 3,Just 3,Just 4]
.
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]
The traverse and sequenceA function in Traversable class must satisfy the following 'naturality' laws:
t . traverse f == traverse (t . f)
t . sequenceA == sequenceA . fmap t
for every 'applicative transformation' t. But what is it?
It doesn't seem to work for instance Traversable [] for t = tail:
Prelude> tail . sequenceA $ [[1],[2,3]]
[[1,3]]
Prelude> sequenceA . fmap tail $ [[1],[2,3]]
[]
Nor for t = join (++) (repeat the list twice):
Prelude Control.Monad> join (++) . sequenceA $ [[1],[2,3]]
[[1,2],[1,3],[1,2],[1,3]]
Prelude Control.Monad> sequenceA . fmap (join (++)) $ [[1],[2,3]]
[[1,2],[1,3],[1,2],[1,3],[1,2],[1,3],[1,2],[1,3]]
So for what t they are satisfied?
The Hackage page for Data.Traversable defines an applicative transformation as follows.
[A]n applicative transformation is a function
t :: (Applicative f, Applicative g) => f a -> g a
preserving the Applicative operations, i.e.
t (pure x) = pure x
t (x <*> y) = t x <*> t y
The simplest example of this would be the identity function. id is an applicative transformation. A more specific example for lists would be reverse.
reverse (pure x) = reverse [x] = [x] = pure x
-- (the (<*>) law is more difficult to show)
And you can verify in GHCi that the laws you reference do hold for reverse.
Prelude> reverse . sequenceA $ [[1], [2,3]]
[[1,3],[1,2]]
Prelude> sequenceA . fmap reverse $ [[1], [2,3]]
[[1,3],[1,2]]
Source: Data.Traversable
I'm new in Haskell.
I can't figure out why we use a monoid and instance Functor Matrix in the code bellow and how instance Functor Matrix works?
instance Functor Matrix where
fmap f (M n m v) = M n m $ fmap (fmap f) v
instance Num a => Num (Matrix a) where
fromInteger = M 1 1 . V.singleton . V.singleton . fromInteger
negate = fmap negate
(+) = add
(*) = mult
abs = fmap abs
signum = fmap signum
scalarMult :: Num a => a -> Matrix a -> Matrix a
scalarMult = fmap . (*)
I know that the functor is necessary for negate, (*), abs, signum, but I need a detailed explanation. Help me, please.
Functors are a very simple thing that have a complicated name. Simply put, Functors are containers that you can map a function over its values, via the fmap function. Lists are the most familiar Functor, since fmap is just map. Other Functors include Maybe, IO, and Either a.
In this snippet you're defining Matrix to be a Functor, so you're telling the compiler that Matrix is a container that it can map functions over. For the purposes of this question, fmap is used to define several of the functions in the Num typeclass. It is pretty easy to see how this works (assuming there is a fromList :: [[a]] -> Matrix a function):
> fmap id $ fromList [[1, 2], [3, 4]]
fromList [[1, 2], [3, 4]]
> fmap (+1) $ fromList [[1, 2], [3, 4]]
fromList [[2, 3], [4, 5]]
> fmap show $ fromList [[1, 2], [3, 4]]
fromList [["1", "2"], ["3", "4"]]
For other Functors:
> fmap (+1) [1, 2, 3]
[2, 3, 4]
> fmap (*10) (Just 1)
Just 10
> fmap (*10) Nothing
Nothing
As for why Data.Monoid is imported in the source for Data.Matrix, it is solely because of the function
-- | Display a matrix as a 'String' using the 'Show' instance of its elements.
prettyMatrix :: Show a => Matrix a -> String
prettyMatrix m#(M _ _ v) = unlines
[ "( " <> unwords (fmap (\j -> fill mx $ show $ m ! (i,j)) [1..ncols m]) <> " )" | i <- [1..nrows m] ]
where
mx = V.maximum $ fmap (V.maximum . fmap (length . show)) v
fill k str = replicate (k - length str) ' ' ++ str
Where the author has opted to use <> instead of ++ for concatenating strings together, a rather mundane use of the list Monoid. It has no relevance at all to the Matrix type.
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