2024-04-15 19:47:57 +02:00
---
title:
- Applicatives
author:
- Sanchayan Maity
theme:
- default
classoption:
- aspectratio=169
---
# Agenda
- Recap of Functors
- Applicative
# Functor[^1][^2]
```haskell
class Functor f where
fmap :: (a -> b) -> f a -> f b
(< $) :: a -> f b -> f a
```
Functors Laws
- Must preserve identity
```haskell
fmap id = id
```
- Must preserve composition of morphism
```haskell
fmap (f . g) == fmap f . fmap g
```
[^1]: [Category Design Pattern ](https://www.haskellforall.com/2012/08/the-category-design-pattern.html )
[^2]: [Functor Design Pattern ](https://www.haskellforall.com/2012/09/the-functor-design-pattern.html )
# Higher order kinds[^3]
- For something to be a functor, it has to be a first order kind.
[^3]: [Haskell's Kind System ](https://diogocastro.com/blog/2018/10/17/haskells-kind-system-a-primer/ )
# Applicative
```haskell
class Functor f => Applicative (f :: TYPE -> TYPE) where
pure :: a -> f a
(< *>) :: f (a -> b) -> f a -> f b
```
```haskell
(< $>) :: Functor f => (a -> b) -> f a -> f b
(< *>) :: Applicative f => f (a -> b) -> f a -> f b
```
```haskell
fmap f x = pure f < *> x
```
# Examples
```haskell
pure (+1) < *> [1..3]
[2, 3, 4]
[(*2), (*3)] < *> [4, 5]
[8,10,12,15]
("Woo", (+1)) < *> (" Hoo!", 0)
("Woo Hoo!", 1)
(Sum 2, (+1)) < *> (Sum 0, 0)
(Sum {getSum = 2}, 1)
(Product 3, (+9)) < *> (Product 2, 8)
(Product {getProduct = 6}, 17)
(,) < $> [1, 2] < *> [3, 4]
[(1,3),(1,4),(2,3),(2,4)]
```
2024-06-25 19:50:51 +02:00
# Use cases[^4]
```haskell
Person
< $> parseString "name" o
< *> parseInt "age" o
< *> parseTelephone "telephone" o
```
Can also be written as
```haskell
liftA3 Person
(parseString "name" o)
(parseInt "age" o)
(parseTelephone "telephone" o)
```
[^4]: [FP Complete - Crash course to Applicative syntax ](https://www.fpcomplete.com/haskell/tutorial/applicative-syntax/ )
# Use cases[^5]
```haskell
parsePerson :: Parser Person
parsePerson = do
string "Name: "
name < - takeWhile ( / = ' n ' )
endOfLine
string "Age: "
age < - decimal
endOfLine
pure $ Person name age
```
[^5]: [FP Complete - Crash course to Applicative syntax ](https://www.fpcomplete.com/haskell/tutorial/applicative-syntax/ )
# Use cases[^6]
```haskell
helper :: () -> Text -> () -> () -> Int -> () -> Person
helper () name () () age () = Person name age
parsePerson :: Parser Person
parsePerson = helper
< $> string "Name: "
< *> takeWhile (/= 'n')
< *> endOfLine
< *> string "Age: "
< *> decimal
< *> endOfLine
```
[^6]: [FP Complete - Crash course to Applicative syntax ](https://www.fpcomplete.com/haskell/tutorial/applicative-syntax/ )
2024-04-15 19:47:57 +02:00
# Lifting
- Seeing Functor as unary lifting and Applicative as n-ary lifting
```haskell
liftA0 :: Applicative f => (a) -> (f a)
liftA1 :: Functor f => (a -> b) -> (f a -> f b)
liftA2 :: Applicative f => (a -> b -> c) -> (f a -> f b -> f c)
liftA3 :: Applicative f => (a -> b -> c -> d) -> (f a -> f b -> f c -> f d)
liftA4 :: Applicative f => ..
```
Where `liftA0 = pure` and `liftA1 = fmap` .
# Monoidal functors
- Remember Monoid?
```haskell
class Monoid m where
mempty :: m
mappend :: m -> m -> m
```
```haskell
($) :: (a -> b) -> a -> b
(< $>) :: (a -> b) -> f a -> f b
(< *>) :: f (a -> b) -> f a -> f b
mappend :: f f f
($) :: (a -> b) -> a -> b
< *> :: f (a -> b) -> f a -> f b
instance Monoid a => Applicative ((,) a) where
pure x = (mempty, x)
(u, f) < *> (v, x) = (u `mappend` v, f x)
```
2024-06-25 19:50:51 +02:00
# Where are monoids again
```haskell
fmap (+1) ("blah", 0)
("blah",1)
("Woo", (+1)) < *> (" Hoo!", 0)
("Woo Hoo!", 1)
(,) < $> [1, 2] < *> [3, 4]
[(1,3),(1,4),(2,3),(2,4)]
liftA2 (,) [1, 2] [3, 4]
[(1,3),(1,4),(2,3),(2,4)]
```
2024-04-15 19:47:57 +02:00
# Function apply
- Applying a function to an `effectful` argument
```haskell
(< $>) :: Functor m => (a -> b) -> m a -> m b
(< *>) :: Applicative m => m (a -> b) -> m a -> m b
(=< < ) :: Monad m => (a -> m b) -> m a -> m b
```
# Contrasts with monad
- No data dependency between `f a` and `f b`
- Result of `f a` can't possibly influence the behaviour of `f b`
- That needs something like `a -> f b`
# Applicative laws
```haskell
-- Identity
pure id < *> v = v
-- Composition
pure (.) < *> u < *> v < *> w = u < *> (v < *> w)
-- Homomorphism
pure f < *> pure x = pure (f x)
-- Interchange
u < *> pure y = pure ($ y) < *> u
```
2024-06-25 19:50:51 +02:00
# Operators[^7]
- `pure` wraps up a pure value into some kind of Applicative
- `liftA2` applies a pure function to the values inside two `Applicative` wrapped values
- `<$>` operator version of `fmap`
- `<*>` apply a wrapped function to a wrapped value
- `*>` , `<*`
[^7]: [FP Complete - Crash course to Applicative syntax ](https://www.fpcomplete.com/haskell/tutorial/applicative-syntax/ )
2024-04-15 19:47:57 +02:00
# Applicative vs monads
- Applicative
* Effects
* Batching and aggregation
* Concurrency/Independent
- Parsing context free grammar
2024-06-25 19:50:51 +02:00
- Exploring all branches of computation (see [`Alternative` ](https://hackage.haskell.org/package/base-4.20.0.1/docs/Control-Applicative.html#t:Alternative ))
2024-04-15 19:47:57 +02:00
- Monads
* Effects
* Composition
* Sequence/Dependent
- Parsing context sensitive grammar
- Branching on previous results
# Weaker but better
- Weaker than monads but thus also more common
- Lends itself to optimisation (See Facebook's [Haxl ](https://hackage.haskell.org/package/haxl ) project)
- Always opt for the least powerful mechanism to get things done
- No dependency issues or branching? just use applicative
# Resources
- [Applicative Programming with Effects ](https://www.staff.city.ac.uk/~ross/papers/Applicative.html )
- [optparse-applicative ](https://hackage.haskell.org/package/optparse-applicative )
- [Control Applicative ](https://hackage.haskell.org/package/base-4.19.1.0/docs/Control-Applicative.html )
2024-06-25 19:50:51 +02:00
- [Applicative functors for fun & parsing ](https://arunraghavan.net/2018/02/applicative-functors-for-fun-and-parsing/ )
2024-04-15 19:47:57 +02:00
# Questions
- Reach out on
* Email: sanchayan@sanchayanmaity.net
* Mastodon: [sanchayanmaity.com ](https://sanchayanmaity.com/@sanchayan )
* Telegram: [t.me/SanchayanMaity ](https://t.me/SanchayanMaity )
* Blog: [sanchayanmaity.net ](https://sanchayanmaity.net/ )