Se ha denunciado esta presentación.
Utilizamos tu perfil de LinkedIn y tus datos de actividad para personalizar los anuncios y mostrarte publicidad más relevante. Puedes cambiar tus preferencias de publicidad en cualquier momento.
Applicative style
programming
jlgarhdez HaskellMADpepegar
Pepe García
Scala Engineer @ Fidesmo
Co-organizer @ HaskellMad & FP-MAD
Scala fan
Haskell Acolyth
Functional Programming D...
About this talk
Slides are available here:
http://es.slideshare.net/JosLuisGarcaHernndez/applicative-style-programming
Cod...
What are we learning today?
● What are applicatives?
● When do we use them?
● Who is using them?
● How to use them?
jlgarh...
What are applicatives?
Applicatives are an abstraction between functions and monads. And they open the
doors for the so ca...
What are applicatives?
@jlgarhdez
class Functor f => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f ...
What are applicatives?
Let’s understand the typeclass:
It exposes a `pure` function, that puts a value inside the applicat...
What are applicatives?
Do you remember fmap from functors? Try to compare it with <*>
fmap :: (a -> b) -> f a -> f b
(<*>)...
What are applicatives?
Basically an Applicative is a Functor that can also apply a function contained in a
container to ot...
A small example
As an example of Applicative Programming, let’s see how Applicative and
Monadic styles compare:
jlgarhdez ...
A small example
data Person = Person {
name :: String,
lastName :: String
} deriving Show
data Err = String
validateName :...
A small example. Monadic
validatePersonM :: String -> String -> Either String Person
validatePersonM n l = do
vName <- val...
A small example. Applicative
validatePersonA :: String -> String -> Either String Person
validatePersonA n l = Person <$> ...
A small example. Applicative (2)
Why does the previous example work? Let’s dig a bit deeper on it:
Prelude> :t Person
Pers...
A small example. Recap
So, what do we learn from our small example?
Monads are not a silver bullet, and can be replaced ea...
When to use applicatives?
When we need more than a functor, and less than a monad…
Sounds appealing, but WTF is this!?
jlg...
When to use applicatives? Functor
Functor defines containers that can be mapped over.
class Functor f where
fmap :: (a -> ...
When to use applicatives? Monad
Monad defines containers allow operation sequencing!
class Monad m where
(>>=) :: m a -> (...
When to use applicatives?
Some rule-o-thumbs I use for detecting Monad overkill
● import Control.Applicative
● replace ret...
When your do block can be substituted by liftM2/3/4...
When to use applicatives?
validatePersonM :: String -> String -> Ei...
When your operations does not depend on each other
When to use applicatives?
validatePersonM :: String -> String -> Either...
Who uses Applicative?
Applicative is being used all over the place nowadays. Some interesting examples
of its use are:
● H...
How to use Applicatives?
@jlgarhdez
Applicatives are really easy to use. You just need to provide an instance of the
typec...
Or, you can go Free!
jlgarhdez HaskellMADpepegar
Free Applicatives
Create an applicative from any Functor
jlgarhdez HaskellMADpepegar
Free Applicatives.
data Ap f a where
Pure :: a -> Ap f a
Ap :: f a -> Ap f (a -> b) -> Ap f b
@jlgarhdez
jlgarhdez Haskell...
Free Applicatives.
instance Functor (Ap f) where
fmap f (Pure a) = Pure (f a)
fmap f (Ap x y) = Ap x ((f .) <$> y)
instanc...
Free applicatives
@jlgarhdez
Now let’s create a small ADT and create a Free Applicative out of it!
import Control.Applicat...
And a bit of syntax…
getPost :: Id -> Blog Post
getPost id = liftAp $ GetPost id
getAuthor :: Id -> Blog Author
getAuthor ...
Free applicatives
@jlgarhdez
Now, we might want to render a page of our blog:
data Page = Page {
post :: Post,
author :: A...
Now, let’s do Applicative magic!
jlgarhdez HaskellMADpepegar
Free applicatives
@jlgarhdez
With all we have already learned, how would you implement the following?
renderPage :: Id -> ...
Free applicatives
@jlgarhdez
With all we have already learned, how would you implement the following?
renderPage :: Id -> ...
jlgarhdez HaskellMADpepegar
But we are not doing anything in that
renderPage function
jlgarhdez HaskellMADpepegar
Let’s do, let’s interpret!
jlgarhdez HaskellMADpepegar
Free applicatives
@jlgarhdez
First, we need an interpreter. This interpreter is called Natural Transformation in
Category ...
Free applicatives
@jlgarhdez
And, last but not least, wire everything together:
main :: IO ()
main = do
page <- runAp inte...
Abstract Syntax Trees
As you know, the most important part of functional programming is referential
transparency. This mea...
Applicatives AST
As you imagine from our
implementation, this Blog does
nothing, just create values. It does
not go to the...
Monadic AST
And, if we compare this AST with the
one created by its monadic
counterpart, implemented in terms of
monadic b...
Applicative AST. Static Analysis
@jlgarhdez
Applicative functors’ ASTs allow you to explore them from the top down without...
Static Analysis
Analysis of a program that does not evaluate the program.
It is possible with our Applicatives!
jlgarhdez ...
Static Analysis
@jlgarhdez
To demonstrate static analysis, let’s keep with our blog example:
data BlogF a where
GetPost ::...
Static Analysis
@jlgarhdez
Also some convenience functions:
getPost :: Id -> Blog Post
getPost id = liftAp $ GetPost id
ge...
Static Analysis
@jlgarhdez
Then, our renderPage would look like this:
renderPage :: Id -> Id -> Blog Page
renderPage post ...
Static Analysis
@jlgarhdez
And, as explained before, we will need to interpret the AST
interpIO :: BlogF a -> IO a
interpI...
Static Analysis
@jlgarhdez
But, the most amazing thing is that we can calculate the number of operations that
our renderPr...
Static Analysis
@jlgarhdez
But, the most amazing thing is that we can calculate the number of operations that
our renderPr...
Composing Applicative
Functors
Unlike Monads, our Applicatives are closed on composition. This means that you
can provide ...
Composing Applicative Functors
@jlgarhdez
data Product m n a = Product {
first :: m a,
second :: n a
}
instance (Functor m...
Applicative Do Notation
Created at Facebook, ApplicativeDo extension allows you to write Applicative
Code in a more famili...
{-# LANGUAGE ApplicativeDo #-}
renderPage :: Id -> Id -> Blog Page
renderPage postId authorId = do
post <- getPost postId
...
Recap
jlgarhdez HaskellMADpepegar
Recap
● Use more applicatives, they DO ROCK!
● Always separate domain modelling from interpretation (with free applicative...
Bibliography
● Idioms: applicative programming with effects. McBride, Paterson
● The Essence of the Iterator Pattern. Gibb...
Applicative style programming
Applicative style programming
Applicative style programming
Próxima SlideShare
Cargando en…5
×

Applicative style programming

838 visualizaciones

Publicado el

A talk gave to the Haskell Madrid User Group http://www.meetup.com/es-ES/Haskell-MAD/events/233138704/

Publicado en: Software
  • Sé el primero en comentar

Applicative style programming

  1. 1. Applicative style programming jlgarhdez HaskellMADpepegar
  2. 2. Pepe García Scala Engineer @ Fidesmo Co-organizer @ HaskellMad & FP-MAD Scala fan Haskell Acolyth Functional Programming Devotee jlgarhdez HaskellMADpepegar
  3. 3. About this talk Slides are available here: http://es.slideshare.net/JosLuisGarcaHernndez/applicative-style-programming Code is available here: https://github.com/pepegar/Control.Applicative.Talk jlgarhdez HaskellMADpepegar
  4. 4. What are we learning today? ● What are applicatives? ● When do we use them? ● Who is using them? ● How to use them? jlgarhdez HaskellMADpepegar
  5. 5. What are applicatives? Applicatives are an abstraction between functions and monads. And they open the doors for the so called applicative style! jlgarhdez HaskellMADpepegar
  6. 6. What are applicatives? @jlgarhdez class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b jlgarhdez HaskellMADpepegar
  7. 7. What are applicatives? Let’s understand the typeclass: It exposes a `pure` function, that puts a value inside the applicative context And a `<*>` function, that applies a function inside an applicative context to the content of another value with the same applicative context jlgarhdez HaskellMADpepegar
  8. 8. What are applicatives? Do you remember fmap from functors? Try to compare it with <*> fmap :: (a -> b) -> f a -> f b (<*>) :: f (a -> b) -> f a -> f b jlgarhdez HaskellMADpepegar
  9. 9. What are applicatives? Basically an Applicative is a Functor that can also apply a function contained in a container to other container of the same type. Prelude Control.Monad> let fn1 = x-> x * x Prelude Control.Monad> let fn2 = x -> x + 33 Prelude Control.Monad> let fns = [fn1, fn2] Prelude Control.Monad> :t fns fns :: Num a => [a -> a] Prelude Control.Monad> let nums = [1,2,3,4] Prelude Control.Monad> :t nums nums :: Num t => [t] Prelude Control.Monad> fns <*> nums jlgarhdez HaskellMADpepegar
  10. 10. A small example As an example of Applicative Programming, let’s see how Applicative and Monadic styles compare: jlgarhdez HaskellMADpepegar
  11. 11. A small example data Person = Person { name :: String, lastName :: String } deriving Show data Err = String validateName :: String -> Either Err String validateName n = if n == "Pepe" then Right n else Left "name is not Pepe" validateLastName :: String -> Either Err String validateLastName l = if l == "García" then Right l else Left "last name is not García" jlgarhdez HaskellMADpepegar
  12. 12. A small example. Monadic validatePersonM :: String -> String -> Either String Person validatePersonM n l = do vName <- validateName n vLast <- validateLastName l return $ Person vName vLast jlgarhdez HaskellMADpepegar
  13. 13. A small example. Applicative validatePersonA :: String -> String -> Either String Person validatePersonA n l = Person <$> validateName n <*> validateLastName l jlgarhdez HaskellMADpepegar
  14. 14. A small example. Applicative (2) Why does the previous example work? Let’s dig a bit deeper on it: Prelude> :t Person Person :: String -> String -> Person Prelude> :t Person <$> validateName "pepe" Person <$> validateName "pepe" :: Either String (String -> Person) Prelude> :t Person <$> validateName "pepe" <*> validateLastName "Garcia" Person <$> validateName "pepe" <*> validateLastName "Garcia" :: Either String Person jlgarhdez HaskellMADpepegar
  15. 15. A small example. Recap So, what do we learn from our small example? Monads are not a silver bullet, and can be replaced easily by Applicative Functors when ordering is not important. jlgarhdez HaskellMADpepegar
  16. 16. When to use applicatives? When we need more than a functor, and less than a monad… Sounds appealing, but WTF is this!? jlgarhdez HaskellMADpepegar
  17. 17. When to use applicatives? Functor Functor defines containers that can be mapped over. class Functor f where fmap :: (a -> b) -> f a -> f b jlgarhdez HaskellMADpepegar
  18. 18. When to use applicatives? Monad Monad defines containers allow operation sequencing! class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a jlgarhdez HaskellMADpepegar
  19. 19. When to use applicatives? Some rule-o-thumbs I use for detecting Monad overkill ● import Control.Applicative ● replace return with pure, liftM with (<$>) (or fmap or liftA), liftM2 with liftA2, etc, and ap with (<*>) ● If your function signature was Monad m => ..., change to Applicative m => ... (and maybe rename m to f or whatever). jlgarhdez HaskellMADpepegar
  20. 20. When your do block can be substituted by liftM2/3/4... When to use applicatives? validatePersonM :: String -> String -> Either String Person validatePersonM n l = do vName <- validateName n vLast <- validateLastName l return $ Person vName vLast becomes validatePersonA :: String -> String -> Either String Person validatePersonA n l = liftM2 Person $ validateName n $ validateLastName l jlgarhdez HaskellMADpepegar
  21. 21. When your operations does not depend on each other When to use applicatives? validatePersonM :: String -> String -> Either String Person validatePersonM n l = do vName <- validateName n vLast <- validateLastName l return $ Person vName vLast becomes validatePersonA :: String -> String -> Either String Person validatePersonA n l = Person <$> validateName n <*> validateLastName l jlgarhdez HaskellMADpepegar
  22. 22. Who uses Applicative? Applicative is being used all over the place nowadays. Some interesting examples of its use are: ● HAXL. Efficient data access ● CmdTheLine. Command line argument parsing ● Validation. Data validation library ● Attoparsec. ByteString parsing library jlgarhdez HaskellMADpepegar
  23. 23. How to use Applicatives? @jlgarhdez Applicatives are really easy to use. You just need to provide an instance of the typeclass for your data type. data Maybe a = Just a | Nothing instance Applicative Maybe where pure = Just Just f <*> m = fmap f m Nothing <*> _m = Nothing jlgarhdez HaskellMADpepegar
  24. 24. Or, you can go Free! jlgarhdez HaskellMADpepegar
  25. 25. Free Applicatives Create an applicative from any Functor jlgarhdez HaskellMADpepegar
  26. 26. Free Applicatives. data Ap f a where Pure :: a -> Ap f a Ap :: f a -> Ap f (a -> b) -> Ap f b @jlgarhdez jlgarhdez HaskellMADpepegar
  27. 27. Free Applicatives. instance Functor (Ap f) where fmap f (Pure a) = Pure (f a) fmap f (Ap x y) = Ap x ((f .) <$> y) instance Apply (Ap f) where Pure f <.> y = fmap f y Ap x y <.> z = Ap x (flip <$> y <.> z) instance Applicative (Ap f) where pure = Pure Pure f <*> y = fmap f y Ap x y <*> z = Ap x (flip <$> y <*> z) @jlgarhdez jlgarhdez HaskellMADpepegar
  28. 28. Free applicatives @jlgarhdez Now let’s create a small ADT and create a Free Applicative out of it! import Control.Applicative.Free import Control.Applicative type Author = String type Post = String type Id = String data BlogF a where GetPost :: Id -> BlogF Post GetAuthor :: Id -> BlogF Author type Blog a = Ap BlogF a jlgarhdez HaskellMADpepegar
  29. 29. And a bit of syntax… getPost :: Id -> Blog Post getPost id = liftAp $ GetPost id getAuthor :: Id -> Blog Author getAuthor id = liftAp $ GetAuthor id Free applicatives @jlgarhdez jlgarhdez HaskellMADpepegar
  30. 30. Free applicatives @jlgarhdez Now, we might want to render a page of our blog: data Page = Page { post :: Post, author :: Author } deriving Show jlgarhdez HaskellMADpepegar
  31. 31. Now, let’s do Applicative magic! jlgarhdez HaskellMADpepegar
  32. 32. Free applicatives @jlgarhdez With all we have already learned, how would you implement the following? renderPage :: Id -> Id -> Blog Page jlgarhdez HaskellMADpepegar
  33. 33. Free applicatives @jlgarhdez With all we have already learned, how would you implement the following? renderPage :: Id -> Id -> Blog Page renderPage postId authorId = Page <$> getPost postId <*> getAuthor authorId jlgarhdez HaskellMADpepegar
  34. 34. jlgarhdez HaskellMADpepegar
  35. 35. But we are not doing anything in that renderPage function jlgarhdez HaskellMADpepegar
  36. 36. Let’s do, let’s interpret! jlgarhdez HaskellMADpepegar
  37. 37. Free applicatives @jlgarhdez First, we need an interpreter. This interpreter is called Natural Transformation in Category Theory, and transforms a value `f a` into a `g a`. interpIO :: BlogF a -> IO a interpIO (GetPost id) = putStrLn ("getting post " ++ show id ++ " from DB") *> pure "this is the post" interpIO (GetAuthor id) = putStrLn ("getting author " ++ show id ++ " from DB") *> pure "Pepe García" jlgarhdez HaskellMADpepegar
  38. 38. Free applicatives @jlgarhdez And, last but not least, wire everything together: main :: IO () main = do page <- runAp interpIO $ renderPage 1 1 print page jlgarhdez HaskellMADpepegar
  39. 39. Abstract Syntax Trees As you know, the most important part of functional programming is referential transparency. This means creating values, not executing effects. That’s what our free applicatives does, they create little programs, or Abstract Syntax Trees jlgarhdez HaskellMADpepegar
  40. 40. Applicatives AST As you imagine from our implementation, this Blog does nothing, just create values. It does not go to the DB to fetch users/posts/whatever. It just creates what is called an Abstract Syntax Tree jlgarhdez HaskellMADpepegar
  41. 41. Monadic AST And, if we compare this AST with the one created by its monadic counterpart, implemented in terms of monadic bind, we can see something interesting. We need to evaluate getPost 1 in order to evaluate getAuthor 1 jlgarhdez HaskellMADpepegar
  42. 42. Applicative AST. Static Analysis @jlgarhdez Applicative functors’ ASTs allow you to explore them from the top down without evaluating a single line of code! This technique is called static analysis, and is awesome for: ● Optimizing performance (deduplicate requests, in a series of HTTP requests) ● Calculate dependencies automatically ● Lint your code jlgarhdez HaskellMADpepegar
  43. 43. Static Analysis Analysis of a program that does not evaluate the program. It is possible with our Applicatives! jlgarhdez HaskellMADpepegar
  44. 44. Static Analysis @jlgarhdez To demonstrate static analysis, let’s keep with our blog example: data BlogF a where GetPost :: Id -> BlogF Post GetAuthor :: Id -> BlogF Author GetComments :: Id -> BlogF [(Comment, Author)] type Blog a = Ap BlogF a jlgarhdez HaskellMADpepegar
  45. 45. Static Analysis @jlgarhdez Also some convenience functions: getPost :: Id -> Blog Post getPost id = liftAp $ GetPost id getAuthor :: Id -> Blog Author getAuthor id = liftAp $ GetAuthor id getComments :: Id -> Blog [(Comment, Author)] getComments id = liftAp $ GetComments id jlgarhdez HaskellMADpepegar
  46. 46. Static Analysis @jlgarhdez Then, our renderPage would look like this: renderPage :: Id -> Id -> Blog Page renderPage post author = Page <$> getPost post <*> getAuthor author <*> getComments post jlgarhdez HaskellMADpepegar
  47. 47. Static Analysis @jlgarhdez And, as explained before, we will need to interpret the AST interpIO :: BlogF a -> IO a interpIO (GetPost id) = putStrLn ("getting post " ++ show id ++ " from DB") *> pure "this is the post" interpIO (GetAuthor id) = putStrLn ("getting author " ++ show id ++ " from DB") *> pure "@pepe" interpIO (GetComments id) = putStrLn ("getting comments for post " ++ show id ++ " from DB") *> pure [ ("this post rocks" , "@anler"), ("you're right, @anler" , "@lorenzo"), ("Oh boy, I love haskell so bad!" , "@dani"), ("Indeed, Haskell is better than Erlang!" , "@joseluis" ) ] jlgarhdez HaskellMADpepegar
  48. 48. Static Analysis @jlgarhdez But, the most amazing thing is that we can calculate the number of operations that our renderProgram does, for example: instance Monoid Int where mempty = 0 mappend = (+) countInstructions :: BlogF a -> Int countInstructions _ = 1 jlgarhdez HaskellMADpepegar
  49. 49. Static Analysis @jlgarhdez But, the most amazing thing is that we can calculate the number of operations that our renderProgram does, for example: main :: IO () main = do putStrLn "NUMBER OF REQUESTS TO THE DB:" print instructions putStrLn "" putStrLn "PAGE RENDERING:" page <- runAp interpIO page print page where instructions = runAp_ countInstructions page page = renderPage 1 1 jlgarhdez HaskellMADpepegar
  50. 50. Composing Applicative Functors Unlike Monads, our Applicatives are closed on composition. This means that you can provide an instance of Applicative for the product of any other two applicatives! jlgarhdez HaskellMADpepegar
  51. 51. Composing Applicative Functors @jlgarhdez data Product m n a = Product { first :: m a, second :: n a } instance (Functor m, Functor n) => Functor (Product m n) where fmap f fa = Product (f <$> first fa) (f <$> second fa) instance (Applicative m, Applicative n) => Applicative (Product m n) where pure x = Product (pure x) (pure x) mf <*> mx = Product (first mf <*> first mx) (second mf <*> second mx) jlgarhdez HaskellMADpepegar
  52. 52. Applicative Do Notation Created at Facebook, ApplicativeDo extension allows you to write Applicative Code in a more familiar fashion, if you come from imperative programming. jlgarhdez HaskellMADpepegar
  53. 53. {-# LANGUAGE ApplicativeDo #-} renderPage :: Id -> Id -> Blog Page renderPage postId authorId = do post <- getPost postId author <- getAuthor authorId return $ Page post author ApplicativeDo @jlgarhdez jlgarhdez HaskellMADpepegar
  54. 54. Recap jlgarhdez HaskellMADpepegar
  55. 55. Recap ● Use more applicatives, they DO ROCK! ● Always separate domain modelling from interpretation (with free applicatives) ● Eliminate boilerplate with meta-programming (with static analysis) ● Keep writing your code in do-block style (with ApplicativeDo) ● Have fun! ● Bonus point: Convince your boss to use Haskell! jlgarhdez HaskellMADpepegar
  56. 56. Bibliography ● Idioms: applicative programming with effects. McBride, Paterson ● The Essence of the Iterator Pattern. Gibbons, Oliveira ● Origami programming. Gibbons ● Static Analysis with Applicatives. Gergő Érdi jlgarhdez HaskellMADpepegar

×