An abstraction that inherits from a Functors which allows passing multiple arguments to the mapped functions.
An applicative implements two functions:
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f bpure wraps a value inside a context.
<*> applies a function inside a context to another argument inside the same context and produces a value inside this context.
Derived operators
Other applicative operators that follows from the definitions of <*> are:
<* :: Applicative f => f a -> f b -> f awhich takes two applicative (or monadic) computations and return the value of the first operand.
*> :: Applicative f => f a -> f b -> f bwhich takes two applicative (or monadic) and return the value of the second operand.
These are useful when we need to perform operations (like parsing) that however do not produce any interesting values.
Applicative Laws
In addition to implementing pure and <*> applicatives must adhere to the following laws
pure id <*> x = x
pure (g x) = pure g <*> pure x
x <*> pure y = pure (\g -> g y) <*> x
x <*> (y <*> z) = (pure (.) <*> x <*> y) <*> zExamples
Defining an applicative
instance Applicative ((->) r) where
-- General pure :: a -> f a
-- pure :: a -> (r -> a)
pure x = const
-- General (<*>) :: f (a -> b) -> f a -> f b
-- (<*>) :: (r -> (a -> b)) -> (r -> a) -> (r -> b)
-- left:
-- g :: r -> (a -> b)
-- h :: r -> a
-- g <*> h :: r -> b
-- right:
-- x :: r
-- \x -> g x :: r -> (a -> b)
-- h x :: a
-- \x -> g x (h x) :: r -> b
g <*> h = \x -> g x (h x)Using *> in applicative parsing.
When parsing booleans one can define such a parsing functions as
pBool :: Parser Bool
pBool =
choice
[ do
lKeyword "true"
pure True,
do
lKeyword "false"
pure False
]However since we only need to check if lKeyword fails when evaluated and not the
resulting value, we can rewrite this function using *>
pBool :: Parser Bool
pBool =
choice
[ lKeyword "true" *> pure True,
lKeyword "false" *> pure False
]