Last active
August 29, 2015 14:26
-
-
Save kisom/09e471e145bf1eca9124 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> import Control.Applicative | |
This post is a [literate | |
Haskell](https://gist.github.com/kisom/09e471e145bf1eca9124) file, | |
converted to org-mode with [Pandoc](http://pandoc.org). | |
Time to explore the `Applicative` type. | |
First, `fmap`: | |
fmap :: (Functor f) => (a -> b) -> f a -> b | |
A Functor applies some transformation on the values | |
of two functors. For example, | |
> maybeShow :: (Show a) => Maybe a -> Maybe String | |
> maybeShow x = show `fmap` x | |
```haskell | |
GHCi> maybeShow $ Just 1 | |
Just "1" | |
GHCi> show `fmap` Just 1 | |
Just "1" | |
GHCi> maybeShow Nothing | |
Nothing | |
``` | |
There's a shortcut for `fmap` exported in | |
`Control.Applicative`: `<$>`. | |
> maybeShow' :: (Show a) => Maybe a -> Maybe String | |
> maybeShow' = (show <$>) | |
```haskell | |
GHCi> show <$> Just 1 | |
Just "1" | |
``` | |
Applicative is short for "Applicative Functor"; it | |
is a functor that can be applied. Basically, `a` is | |
a function; where we had `(a → b)` as the first | |
argument to `fmap`, we now have `f (a → b)`. The | |
`<*>` operator is used for sequential application: | |
```haskell | |
GHCi> :t (<*>) | |
(<*>) :: Applicative a => a (b -> c) -> a b -> a c | |
``` | |
(Note: both `<$>` and `<*>` are left-associative with a | |
priority of 4.) | |
Let's try it this way: | |
> -- Login contains a username and password. | |
> data Login = Login String String deriving (Show) | |
Actually building login code is outside the scope of | |
this, so we'll simulate a scenario where a username can | |
be gotten and one where it can't; similarly for | |
passwords. | |
> getKyleName :: Maybe String | |
> getKyleName = Just "kyle" | |
> | |
> getBadName :: Maybe String | |
> getBadName = Nothing | |
The `Login` constructor basically acts as a function | |
that takes two string arguments and returns a login: | |
``` | |
GHCi> :t Login | |
Login :: String -> String -> Login | |
``` | |
Let's fmap Login with one of our login functions: | |
``` | |
GHCi> :t Login <$> getBadName | |
Login <$> getBadName :: Maybe (String -> Login) | |
``` | |
Notice the return type: it's an `f (a -> b)`. Let's | |
get some passwords: | |
> getMyPassword :: Maybe String | |
> getMyPassword = Just "password" | |
> | |
> getNoPassword :: Maybe String | |
> getNoPassword = Nothing | |
```haskell | |
GHCi> Login <$> getBadName <*> getNoPassword | |
Nothing | |
GHCi> Login <$> getKyleName <*> getMyPassword | |
Just (Login "kyle" "password") | |
GHCi> Login <$> getKyleName <*> getNoPassword | |
Nothing | |
GHCi> Login <$> getBadName <*> getMyPassword | |
Nothing | |
``` | |
If any of the steps in the computation return `Nothing`, | |
the whole result is `Nothing`. | |
Notice `fmap` is used to parameterise the root value, | |
building a function from this. Successive links in | |
the application chain build on this. Imagine the | |
following: | |
> -- A flight crew has a commander, pilot, engineer, | |
> -- and medic. | |
> data FlightCrew = Crew String String String String | |
> deriving (Show) | |
> onePossibleCrew = Crew | |
> <$> Just "Mal" | |
> <*> Just "Wash" | |
> <*> Just "Kaylee" | |
> <*> Just "Book" | |
If we couldn't fill any of the roles, we wouldn't have | |
a crew. | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment