Typeclassopedia presents the following exercise:
Implement pure and (<*>) in terms of unit and (**), and vice versa.
Here's Monoidal and MyApplicative:
class Functor f => Monoidal f where
u :: f () -- using `u` rather than `unit`
dotdot :: f a -> f b -> f (a,b) -- using instead of `(**)`
class Functor f => MyApplicative f where
p :: a -> f a -- using instead of `pure`
apply :: f (a -> b) -> f a -> f b -- using instead of `(<**>)`
First, let me show the Maybe-like data type:
data Option a = Some a
| None deriving Show
Then, I defined instance MyApplicative Option:
instance MyApplicative Option where
p = Some
apply None _ = None
apply _ None = None
apply (Some g) f = fmap g f
Finally, my attempt at implementing Monoidal Option in terms of p and apply of MyApplicative:
instance Monoidal Option where
u = p ()
dotdot None _ = None
dotdot _ None = None
dotdot (Some x) (Some y) = Some id <*> Some (x, y)
Is this right? My implementation of dotdot with apply doesn't seem
instance Monoidal Option where
u = p ()
dotdot None _ = None
dotdot _ None = None
dotdot (Some x) (Some y) = apply (Some id) (Some (x, y))
In particular, I'm curious about how to properly implement dotdot :: f a -> f b -> f (a, b) with Applicative's (<*>) - in my case it's apply.
Applicative is a neat alternative presentation of Monoidal. Both typeclasses are equivalent, and you can convert between the two without considering a specific data type like Option. The "neat alternative presentation" for Applicative is based on the following two equivalencies
pure a = fmap (const a) unit
unit = pure ()
ff <*> fa = fmap (\(f,a) -> f a) $ ff ** fa
fa ** fb = pure (,) <*> fa <*> fb
The trick to get this "neat alternative presentation" for Applicative is the same as the trick for zipWith - replace explicit types and constructors in the interface with things that the type or constructor can be passed into to recover what the original interface was.
unit :: f ()
is replaced with pure which we can substitute the type () and the constructor () :: () into to recover unit.
pure :: a -> f a
pure () :: f ()
And similarly (though not as straightforward) for substituting the type (a,b) and the constructor (,) :: a -> b -> (a,b) into liftA2 to recover **.
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 (,) :: f a -> f b -> f (a,b)
Applicative then gets the nice <*> operator by lifting function application ($) :: (a -> b) -> a -> b into the functor.
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 ($)
Getting from <*> back to liftA2 is common enough that liftA2 is included in Control.Applicative. The <$> is infix fmap.
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = f <$> a <*> b
Related
How Can I instantiate the following data types to be Functor ?
data LiftItOut f a = LiftItOut (f a)
data Parappa f g a = DaWrappa (f a) (g a)
data IgnoreOne f g a b = IgnoringSomething (f a) (g b)
data Notorious g o a t = Notorious (g o) (g a) (g t)
There are not very clear for the declaration themselves, inside the parantheses in the right member, is that function application (I ve never seen that, only basic type constructors)? I am new to haskell and I am just trying to understand the basics.
Ask the compiler to show you how. Use the command line flag -ddump-deriv, enable the DeriveFunctor language extension, and put deriving Functor at the end of each type definition, and then the compiler will print Functor instances for each of them:
==================== Derived instances ====================
Derived class instances:
instance GHC.Base.Functor g =>
GHC.Base.Functor (Main.Notorious g o a) where
GHC.Base.fmap f_aK1 (Main.Notorious a1_aK2 a2_aK3 a3_aK4)
= Main.Notorious a1_aK2 a2_aK3 (GHC.Base.fmap f_aK1 a3_aK4)
(GHC.Base.<$) z_aK5 (Main.Notorious a1_aK6 a2_aK7 a3_aK8)
= Main.Notorious a1_aK6 a2_aK7 ((GHC.Base.<$) z_aK5 a3_aK8)
instance forall k (f :: k -> *) (g :: * -> *) (a :: k).
GHC.Base.Functor g =>
GHC.Base.Functor (Main.IgnoreOne f g a) where
GHC.Base.fmap f_aK9 (Main.IgnoringSomething a1_aKa a2_aKb)
= Main.IgnoringSomething a1_aKa (GHC.Base.fmap f_aK9 a2_aKb)
(GHC.Base.<$) z_aKc (Main.IgnoringSomething a1_aKd a2_aKe)
= Main.IgnoringSomething a1_aKd ((GHC.Base.<$) z_aKc a2_aKe)
instance (GHC.Base.Functor f, GHC.Base.Functor g) =>
GHC.Base.Functor (Main.Parappa f g) where
GHC.Base.fmap f_aKf (Main.DaWrappa a1_aKg a2_aKh)
= Main.DaWrappa
(GHC.Base.fmap f_aKf a1_aKg) (GHC.Base.fmap f_aKf a2_aKh)
(GHC.Base.<$) z_aKi (Main.DaWrappa a1_aKj a2_aKk)
= Main.DaWrappa
((GHC.Base.<$) z_aKi a1_aKj) ((GHC.Base.<$) z_aKi a2_aKk)
instance GHC.Base.Functor f =>
GHC.Base.Functor (Main.LiftItOut f) where
GHC.Base.fmap f_aKl (Main.LiftItOut a1_aKm)
= Main.LiftItOut (GHC.Base.fmap f_aKl a1_aKm)
(GHC.Base.<$) z_aKn (Main.LiftItOut a1_aKo)
= Main.LiftItOut ((GHC.Base.<$) z_aKn a1_aKo)
That's kind of messy-looking, but it's rather straightforward to clean up:
data LiftItOut f a = LiftItOut (f a)
instance Functor f => Functor (LiftItOut f) where
fmap f (LiftItOut a) = LiftItOut (fmap f a)
data Parappa f g a = DaWrappa (f a) (g a)
instance (Functor f, Functor g) => Functor (Parappa f g) where
fmap f (DaWrappa a1 a2) = DaWrappa (fmap f a1) (fmap f a2)
data IgnoreOne f g a b = IgnoringSomething (f a) (g b)
instance Functor g => Functor (IgnoreOne f g a) where
fmap f (IgnoringSomething a1 a2) = IgnoringSomething a1 (fmap f a2)
data Notorious g o a t = Notorious (g o) (g a) (g t)
instance Functor g => Functor (Notorious g o a) where
fmap f (Notorious a1 a2 a3) = Notorious a1 a2 (fmap f a3)
Also worth noting that your LiftItOut is isomorphic to Ap and IdentityT, and your Parappa is isomorphic to Product.
A functor f is a type constructor with an associated function fmap that from a function of type (a -> b) creates a function of type (f a) -> (f b) which applies it "on the inside": (the parentheses are redundant and are used for clarity/emphasis only)
fmap :: (Functor f) => ( a -> b)
-> (f a) -> (f b)
-- i.e. g :: a -> b -- from this
-- --------------------------
-- fmap g :: (f a) -> (f b) -- we get this
(read it "fmap of g from a to b goes from f a to f b").
Put differently, something being a "Functor" means that it can be substituted for f in
fmap id (x :: f a) = x
(fmap g . fmap h) = fmap (g . h)
so that the expressions involved make sense (i.e. are well formed, i.e. have a type), and, importantly, the above equations hold -- they are in fact the two "Functor laws".
You have
data LiftItOut h a = MkLiftItOut (h a) -- "Mk..." for "Make..."
------------- ----------- ------
new type, data type of the data constructor's
defined here constructor one argument (one field)
This means h a is a type of a thing which can serve as an argument to MkLiftItOut. For example, Maybe Int (i.e. h ~ Maybe and a ~ Int), [(Float,String)] (i.e. h ~ [] and a ~ (Float,String)), etc.
h, a are type variables -- meaning, they can be replaced by any specific type so that the whole syntactic expressions make sense.
These syntactic expressions include MkLiftItOut x which is a thing of type LiftItOut h a provided x is a thing of type h a; LiftItOut h a which is a type; h a which is a type of a thing which can appear as an argument to MkLiftItOut. Thus we can have in our programs
v1 = MkLiftItOut ([1,2,3] :: [] Int ) :: LiftItOut [] Int
v2 = MkLiftItOut ((Just "") :: Maybe String) :: LiftItOut Maybe String
v3 = MkLiftItOut (Nothing :: Maybe () ) :: LiftItOut Maybe ()
.....
etc. Then we have
ghci> :i Functor
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
(<$) :: a -> f b -> f a
..........
This means that Functor f => (f a) is a type of a thing which a variable can reference, e.g.
-- f a
v4 = Just 4 :: Maybe Int
v41 = 4 :: Int
v5 = [4.4, 5.5] :: [] Float
v51 = 4.4 :: Float
v52 = 5.5 :: Float
v6 = (1,"a") :: ((,) Int) String -- or simpler, `(Int, String)`
v61 = "a" :: String
v7 = (\x -> 7) :: ((->) Int) Int -- or simpler, `Int -> Int`
Here a is a type of a thing, f a is a type of a thing, f is a type which, when given a type of a thing, becomes a type of a thing; etc. There's no thing which can be referenced by a variable which would have the type f on its own.
All the above fs are instances of the Functor typeclass. This means that somewhere in the libraries there are definitions of
instance Functor Maybe where ....
instance Functor [] where ....
instance Functor ((,) a) where ....
instance Functor ((->) r) where ....
Notice we always have the f, and the a. f in particular can be made of more than one constituents, but a is always some one type.
Thus in this case we must have
instance Functor (LiftItOut h) where ....
(...why? do convince yourself in this; see how all the above statements apply and are correct)
Then the actual definition must be
-- fmap :: (a -> b) -> f a -> f b
-- fmap :: (a -> b) -> LiftItOut h a -> LiftItOut h b
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
y = ....
In particular, we'll have
-- g :: a -> b -- x :: (h a) -- y :: (h b)
and we don't even know what the h is.
How can we solve this? How can we construct an h b-type of thing from an h a-type of thing when we don't even know anything about h, a, nor b?
We can't.
But what if we knew that h is also a Functor?
instance (Functor h) => Functor (LiftItOut h) where
-- fmap :: (a -> b) -> (f a) -> (f b)
-- fmap :: (a -> b) -> (LiftItOut h a) -> (LiftItOut h b)
fmap g (MkLiftItOut x ) = (MkLiftItOut y )
where
-- fmap :: (a -> b) -> (h a) -> (h b)
y = ....
Hopefully you can finish this up. And also do the other types in your question as well. If not, post a new question for the one type with which you might have any further problems.
Applicatives are often presented as a way to lift multi-argument functions
into a functor and apply functor values to it. But I wonder if there is some
subtle additional power stemming from the fact that it can do so by lifting
functions that return a function and applying the function arguments one at
a time.
Imagine instead we define an interface based on lifting functions whose argument is a tuple of arguments:
# from Functor
fmap :: (a -> b) -> Fa -> Fb
# from Applicative
pure :: a -> Fa
# combine multiple functor values into a functor of a tuple
tuple1 :: Fa -> F(a)
tuple2 :: Fa -> Fb -> F(a,b)
tuple3 :: Fa -> Fb -> Fc -> F(a,b,c)
(etc ...)
# lift multi-argument functions (that take a tuple as input)
ap_tuple1 :: ((a) -> b) -> F(a) -> Fb
ap_tuple2 :: ((a,b) -> c) -> F(a,b) -> Fc
ap_tuple3 :: ((a,b,c) -> d) -> F(a,b,c) -> Fd
(etc ..)
Assume we had the corresponding tuple function defined for every sized tuple we may encounter.
Would this interface be equally as powerful as the Applicative interface, given it allows for
lifting/applying-to multi-argument functions BUT doesn't allow for lifting/applying-to functions
that return a function? Obviously one can curry functions that take a tuple as an argument
so they can be lifted in an applicative and one can uncurry functions that return a function
in order to lift them into hypothetical implementation above. But to my mind there is a subtle
difference in power. Is there any difference? (Assuming the question even makes sense)
You've rediscovered the monoidal presentation of Applicative. It looks like this:
class Functor f => Monoidal f where
(>*<) :: f a -> f b -> f (a, b)
unit :: f ()
It's isomorphic to Applicative via:
(>*<) = liftA2 (,)
unit = pure ()
pure x = x <$ unit
f <*> x = fmap (uncurry ($)) (f >*< x)
By the way, your ap_tuple functions are all just fmap. The "hard" part with multiple values is combining them together. Splitting them back into pieces is "easy".
Yes, this is equally as powerful. Notice that pure and tuple1 are the same. Further, everything higher than tuple2 is recovered from tuple2 and fmap:
tuple3 x y z = repair <$> tuple2 (tuple2 x y) z
where repair ((a, b), c) = (a, b, c)
tuple4 w x y z = repair <$> tuple2 (tuple2 x y) (tuple2 x y)
where repair ((a, b), (c, d)) = (a, b, c, d)
-- etc.
Also, all of the ap_tuples are just fmap:
ap_tuple1 = fmap
ap_tuple2 = fmap
ap_tuple3 = fmap
-- ...
Renaming prod = tuple2, your question boils down to
Is
class Functor f => Applicative f where
pure :: a -> f a
prod :: f a -> f b -> f (a, b)
equivalent to
class Functor f => Applicative f where
pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
?
And you might already see that the answer is yes. prod is just a specialization of liftA2
prod = liftA2 (,)
But (,) is "natural" in the sense that it doesn't "delete" anything, so you can recover liftA2 just by destructuring the data back out:
liftA2 f x y = f' <$> prod x y
where f' (a, b) = f a b
I came across this discussion on the Haskell mailing list. From the discussion, there seems to be performance implications with adding liftA2 as a method of Applicative. Can you provide concrete examples why it is necessary to add liftA2 to Applicative methods?
The email is written in 2017. At that time the Applicative typeclass looked like:
class Functor f => Applicative f where
-- | Lift a value.
pure :: a -> f a
-- | Sequential application.
(<*>) :: f (a -> b) -> f a -> f b
-- | Sequence actions, discarding the value of the first argument.
(*>) :: f a -> f b -> f b
a1 *> a2 = (id <$ a1) <*> a2
-- This is essentially the same as liftA2 (const id), but if the
-- Functor instance has an optimized (<$), we want to use that instead.
-- | Sequence actions, discarding the value of the second argument.
(<*) :: f a -> f b -> f a
(<*) = liftA2 const
So without the liftA2 as part of the Applicative typeclass. It was defined as [src]:
liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c
liftA2 f a b = fmap f a <*> b
so one could not make a special implementation in the typeclass. This means that sometimes liftA2 can be implemented more efficiently, but one can not define that.
For example the Maybe functor and Applicative are implemented as:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
instance Applicative Maybe where
pure = Just
Just f <*> Just x = Just (f x)
_ <*> _ = Nothing
This thus means that the liftA2 for a Maybe is implemented similar to:
liftA2Maybe :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
liftA2Maybe f x y = apMaybe (fmapMaybe f x) y
where fmapMaybe f (Just x) = Just (f x)
fmapMaybe _ Nothing = Nothing
apMaybe (Just f) (Just x) = Just (f x)
apMaybe _ _ = Nothing
But this is not optimal. It means that fmapMaybe will inspect if the parameter is a Just x, or Nothing, and then return a Just (f x) or a Nothing. But regardless, apMaybe will again inspect that, whereas we can already know that in advance. We can make a more efficient implementation with:
liftA2Maybe :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c
liftA2Maybe f (Just x) (Just y) = Just (f x y)
liftA2Maybe _ _ _ = Nothing
here we avoid extra unpacking of data constructors. This is not that problematic however. For certain data structures like a ZipList the overhead will be more severe because the number of objects is larger.
On June 23, 2017, a new base library was published where the liftA2 function was added as a method to the Applicative type class.
class Applicative f => Monad f where
return :: a -> f a
(>>=) :: f a -> (a -> f b) -> f b
(<*>) can be derived from pure and (>>=):
fs <*> as =
fs >>= (\f -> as >>= (\a -> pure (f a)))
For the line
fs >>= (\f -> as >>= (\a -> pure (f a)))
I am confused by the usage of >>=. I think it takes a functor f a and a function, then return another functor f b. But in this expression, I feel lost.
Lets start with the type we're implementing:
(<*>) :: Monad f => f (a -> b) -> f a -> f b
(The normal type of <*> of course has an Applicative constraint, but here we're trying to use Monad to implement Applicative)
So in fs <*> as = _, fs is an "f of functions" (f (a -> b)), and as is an "f of as".
We'll start by binding fs:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= _
If you actually compile that, GHC will tell us what type the hole (_) has:
foo.hs:4:12: warning: [-Wtyped-holes]
• Found hole: _ :: (a -> b) -> f b
Where: ‘a’, ‘f’, ‘b’ are rigid type variables bound by
the type signature for:
(Main.<*>) :: forall (f :: * -> *) a b.
Monad f =>
f (a -> b) -> f a -> f b
at foo.hs:2:1-45
That makes sense. Monad's >>= takes an f a on the left and a function a -> f b on the right, so by binding an f (a -> b) on the left the function on the right gets to receive an (a -> b) function "extracted" from fs. And provided we can write a function that can use that to return an f b, then the whole bind expression will return the f b we need to meet the type signature for <*>.
So it'll look like:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> _)
What can we do there? We've got f :: a -> b, and we've still got as :: f a, and we need to make an f b. If you're used to Functor that's obvious; just fmap f as. Monad implies Functor, so this does in fact work:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> fmap f as)
It's also, I think, a much easier way to understand the way Applicative can be implemented generically using the facilities from Monad.
So why is your example written using another >>= and pure instead of just fmap? It's kind of harkening back to the days when Monad did not have Applicative and Functor as superclasses. Monad always "morally" implied both of these (since you can implement Applicative and Functor using only the features of Monad), but Haskell didn't always require there to be these instances, which leads to books, tutorials, blog posts, etc explaining how to implement these using only Monad. The example line given is simply inlining the definition of fmap in terms of >>= and pure (return)1.
I'll continue to unpack as if we didn't have fmap, so that it leads to the version you're confused by.
If we're not going to use fmap to combine f :: a -> b and as :: f a, then we'll need to bind as so that we have an expression of type a to apply f to:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> _))
Inside that hole we need to make an f b, and we have f :: a -> b and a :: a. f a gives us a b, so we'll need to call pure to turn that into an f b:
(<*>) :: Monad f => f ( a -> b) -> f a -> f b
fs <*> as
= fs >>= (\f -> as >>= (\a -> pure (f a)))
So that's what this line is doing.
Binding fs :: f (a -> b) to get access to an f :: a -> b
Inside the function that has access to f it's binding as to get access to a :: a
Inside the function that has access to a (which is still inside the function that has access to f as well), call f a to make a b, and call pure on the result to make it an f b
1 You can implement fmap using >>= and pure as fmap f xs = xs >>= (\x -> pure (f x)), which is also fmap f xs = xs >>= pure . f. Hopefully you can see that the inner bind of your example is simply inlining the first version.
Applicative is a Functor. Monad is also a Functor. We can see the "Functorial" values as standing for computations of their "contained" ⁄ produced pure values (like IO a, Maybe a, [] a, etc.), as being the allegories of ⁄ metaphors for the various kinds of computations.
Functors describe ⁄ denote notions ⁄ types of computations, and Functorial values are reified computations which are "run" ⁄ interpreted in a separate step which is thus akin to that famous additional indirection step by adding which, allegedly, any computational problem can be solved.
Both fs and as are your Functorial values, and bind ((>>=), or in do notation <-) "gets" the carried values "in" the functor. Bind though belongs to Monad.
What we can implement in Monad with (using return as just a synonym for pure)
do { f <- fs ; -- fs >>= ( \ f -> -- fs :: F (a -> b) -- f :: a -> b
a <- as ; -- as >>= ( \ a -> -- as :: F a -- a :: a
return (f a) -- return (f a) ) ) -- f a :: b
} -- :: F b
( or, with MonadComprehensions,
[ f a | f <- fs, a <- as ]
), we get from the Applicative's <*> which expresses the same computation combination, but without the full power of Monad. The difference is, with Applicative as is not dependent on the value f there, "produced by" the computation denoted by fs. Monadic Functors allow such dependency, with
[ bar x y | x <- xs, y <- foo x ]
but Applicative Functors forbid it.
With Applicative all the "computations" (like fs or as) must be known "in advance"; with Monad they can be calculated -- purely -- based on the results of the previous "computation steps" (like foo x is doing: for (each) value x that the computation xs will produce, new computation foo x will be (purely) calculated, the computation that will produce (some) y(s) in its turn).
If you want to see how the types are aligned in the >>= expressions, here's your expression with its subexpressions named, so they can be annotated with their types,
exp = fs >>= g -- fs >>=
where g f = xs >>= h -- (\ f -> xs >>=
where h x = return (f x) -- ( \ x -> pure (f x) ) )
x :: a
f :: a -> b
f x :: b
return (f x) :: F b
h :: a -> F b -- (>>=) :: F a -> (a -> F b) -> F b
xs :: F a -- xs h
-- <-----
xs >>= h :: F b
g f :: F b
g :: (a -> b) -> F b -- (>>=) :: F (a->b) -> ((a->b) -> F b) -> F b
fs :: F (a -> b) -- fs g
-- <----------
fs >>= g :: F b
exp :: F b
and the types of the two (>>=) applications fit:
(fs :: F (a -> b)) >>= (g :: (a -> b) -> F b)) :: F b
(xs :: F a ) >>= (h :: (a -> F b)) :: F b
Thus, the overall type is indeed
foo :: F (a -> b) -> F a -> F b
foo fs xs = fs >>= g -- foo = (<*>)
where g f = xs >>= h
where h x = return (f x)
In the end, we can see monadic bind as an implementation of do, and treat the do notation
do {
abstractly, axiomatically, as consisting of the lines of the form
a <- F a ;
b <- F b ;
......
n <- F n ;
return (foo a b .... n)
}
(with a, F b, etc. denoting values of the corresponding types), such that it describes the overall combined computation of the type F t, where foo :: a -> b -> ... -> n -> t. And when none of the <-'s right-hand side's expressions is dependent on no preceding left-hand side's variable, it's not essentially Monadic, but just an Applicative computation that this do block is describing.
Because of the Monad laws it is enough to define the meaning of do blocks with just two <- lines. For Functors, just one <- line is allowed ( fmap f xs = do { x <- xs; return (f x) }).
Thus, Functors/Applicative Functors/Monads are EDSLs, embedded domain-specific languages, because the computation-descriptions are themselves values of our language (those to the right of the arrows in do notation).
Lastly, a types mandala for you:
T a
T (a -> b)
(a -> T b)
-------------------
T (T b)
-------------------
T b
This contains three in one:
F a A a M a
a -> b A (a -> b) a -> M b
-------------- -------------- -----------------
F b A b M b
You can define (<*>) in terms of (>>=) and return because all monads are applicative functors. You can read more about this in the Functor-Applicative-Monad Proposal. In particular, pure = return and (<*>) = ap is the shortest way to achieve an Applicative definition given an existing Monad definition.
See the type signatures for (<*>), ap and (>>=):
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
ap :: Monad m => m (a -> b) -> m a -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
The type signature for (<*>) and ap are nearly equivalent. Since ap is written using do-notation, it is equivalent to some use of (>>=). I'm not sure this helps, but I find the definition of ap readable. Here's a rewrite:
ap m1 m2 = do { x1 <- m1; x2 <- m2; return (x1 x2) }
≡ ap m1 m2 = do
x1 <- m1
x2 <- m2
return (x1 x2)
≡ ap m1 m2 =
m1 >>= \x1 ->
m2 >>= \x2 ->
return (x1 x2)
≡ ap m1 m2 = m1 >>= \x1 -> m2 >>= \x2 -> return (x1 x2)
≡ ap mf ma = mf >>= (\f -> ma >>= (\a -> pure (f a)))
Which is your definition. You could show that this definition upholds the applicative functor laws, since not everything defined in terms of (>>=) and return does that.
I am reading in the haskellbook about applicative and trying to understand it.
In the book, the author mentioned:
So, with Applicative, we have a Monoid for our structure and function
application for our values!
How is monoid connected to applicative?
Remark: I don't own the book (yet), and IIRC, at least one of the authors is active on SO and should be able to answer this question. That being said, the idea behind a monoid (or rather a semigroup) is that you have a way to create another object from two objects in that monoid1:
mappend :: Monoid m => m -> m -> m
So how is Applicative a monoid? Well, it's a monoid in terms of its structure, as your quote says. That is, we start with an f something, continue with f anotherthing, and we get, you've guessed it a f resulthing:
amappend :: f (a -> b) -> f a -> f b
Before we continue, for a short, a very short time, let's forget that f has kind * -> *. What do we end up with?
amappend :: f -> f -> f
That's the "monodial structure" part. And that's the difference between Applicative and Functor in Haskell, since with Functor we don't have that property:
fmap :: (a -> b) -> f a -> f b
-- ^
-- no f here
That's also the reason we get into trouble if we try to use (+) or other functions with fmap only: after a single fmap we're stuck, unless we can somehow apply our new function in that new structure. Which brings us to the second part of your question:
So, with Applicative, we have [...] function application for our values!
Function application is ($). And if we have a look at <*>, we can immediately see that they are similar:
($) :: (a -> b) -> a -> b
(<*>) :: f (a -> b) -> f a -> f b
If we forget the f in (<*>), we just end up with ($). So (<*>) is just function application in the context of our structure:
increase :: Int -> Int
increase x = x + 1
five :: Int
five = 5
increaseA :: Applicative f => f (Int -> Int)
increaseA = pure increase
fiveA :: Applicative f => f Int
fiveA = pure 5
normalIncrease = increase $ five
applicativeIncrease = increaseA <*> fiveA
And that's, I guessed, what the author meant with "function application". We suddenly can take those functions that are hidden away in our structure and apply them on other values in our structure. And due to the monodial nature, we stay in that structure.
That being said, I personally would never call that monodial, since <*> does not operate on two arguments of the same type, and an applicative is missing the empty element.
1 For a real semigroup/monoid that operation should be associative, but that's not important here
Although this question got a great answer long ago, I would like to add a bit.
Take a look at the following class:
class Functor f => Monoidal f where
unit :: f ()
(**) :: f a -> f b -> f (a, b)
Before explaining why we need some Monoidal class for a question about Applicatives, let us first take a look at its laws, abiding by which gives us a monoid:
f a (x) is isomorphic to f ((), a) (unit ** x), which gives us the left identity. (** unit) :: f a -> f ((), a), fmap snd :: f ((), a) -> f a.
f a (x) is also isomorphic f (a, ()) (x ** unit), which gives us the right identity. (unit **) :: f a -> f (a, ()), fmap fst :: f (a, ()) -> f a.
f ((a, b), c) ((x ** y) ** z) is isomorphic to f (a, (b, c)) (x ** (y ** z)), which gives us the associativity. fmap assoc :: f ((a, b), c) -> f (a, (b, c)), fmap assoc' :: f (a, (b, c)) -> f ((a, b), c).
As you might have guessed, one can write down Applicative's methods with Monoidal's and the other way around:
unit = pure ()
f ** g = (,) <$> f <*> g = liftA2 (,) f g
pure x = const x <$> unit
f <*> g = uncurry id <$> (f ** g)
liftA2 f x y = uncurry f <$> (x ** y)
Moreover, one can prove that Monoidal and Applicative laws are telling us the same thing. I asked a question about this a while ago.