diff --git a/applicative/Makefile b/applicative/Makefile new file mode 100644 index 0000000..9371581 --- /dev/null +++ b/applicative/Makefile @@ -0,0 +1,11 @@ +all: + make slide slideshow + +slide: + pandoc -t beamer --include-in-header=./style.tex applicative.md -f markdown-implicit_figures -V colorlinks=true -V linkcolor=blue -V urlcolor=red -o applicative.pdf + +slideshow: + pandoc -t beamer --include-in-header=./style.tex applicative.md -f markdown-implicit_figures -V colorlinks=true -V linkcolor=blue -V urlcolor=red -i -o applicative-slideshow.pdf + +view: + zathura --mode=presentation applicative.pdf & diff --git a/applicative/applicative-slideshow.pdf b/applicative/applicative-slideshow.pdf new file mode 100644 index 0000000..fd49b90 Binary files /dev/null and b/applicative/applicative-slideshow.pdf differ diff --git a/applicative/applicative.md b/applicative/applicative.md new file mode 100644 index 0000000..ca7c434 --- /dev/null +++ b/applicative/applicative.md @@ -0,0 +1,193 @@ +--- +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)] +``` + +# 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) +``` + +# 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 +``` + +# Applicative vs monads + +- Applicative + * Effects + * Batching and aggregation + * Concurrency/Independent + - Parsing context free grammar + - Exploring all branches of computation (see `Alternative`) + +- 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) + +# 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/) diff --git a/applicative/applicative.pdf b/applicative/applicative.pdf new file mode 100644 index 0000000..b55e4bf Binary files /dev/null and b/applicative/applicative.pdf differ diff --git a/applicative/style.tex b/applicative/style.tex new file mode 100644 index 0000000..89d7670 --- /dev/null +++ b/applicative/style.tex @@ -0,0 +1 @@ +\logo{\includegraphics[height=0.5cm]{../images/Haskell.jpg}\vspace{220pt}\hspace{8pt}}