Maybe
data type defines two related contexts: data Maybe a = Nothing | Just a
Just a
versus Nothing
. But first, let's talk about functors!fmap
to the rescue. fmap
is a guy from the street, fmap
knows a lot about contexts. He knows how to apply a function to a value wrapped in a context. Let's say that you want to apply (+3)
to Just 2
. Use fmap
: > fmap (+3) (Just 2) Just 5
fmap
showed us how to do it! But how does he know how to properly apply a function?fmap
is applied to it. This is how fmap
works: > fmap (+3) (Just 2) Just 5
fmap
magically apply this function, because Maybe
is a functor. It defines how to apply functions to Just
's and Nothing
's: instance Functor Maybe where fmap func (Just val) = Just (func val) fmap func Nothing = Nothing
fmap (+3) (Just 2)
:fmap
, and apply, please, (+3)
to Nothing
." > fmap (+3) Nothing Nothing
fmap
knows what to do; you started with Nothing
and finish with Nothing
too! This is fmap
zen. And now it is clear why the data type Maybe
exists. For example, how would you work with a record in a database in a language without Maybe
: post = Post.find_by_id(1) if post return post.title else return nil end
fmap (getPostTitle) (findPost 1)
findPost
returns a message, then we display its header using getPostTitle
. If it returns Nothing
, then we return Nothing
! Damn graceful, huh?<$>
Is the infix version of fmap
, so instead of the code above you can often find: getPostTitle <$> (findPost 1)
instance Functor [] where fmap = map
fmap (+3) (+1)
> import Control.Applicative > let foo = fmap (+3) (+2) > foo 10 15
instance Functor ((->) r) where fmap fg = f . g
fmap
to a function, you simply make a composition of functions!Control.Applicative
defines a <*>
that knows how to apply a function wrapped in a context to a value wrapped in a context : Just (+3) <*> Just 2 == Just 5
<*>
can lead to interesting situations. For example: > [(*2), (+3)] <*> [1, 2, 3] [2, 4, 6, 4, 5, 6]
> (+) <$> (Just 5) Just (+5) > Just (+5) <$> (Just 4) ??? JUST
> (+) <$> (Just 5) Just (+5) > Just (+5) <*> (Just 3) Just 8
Applicative
technically pushes Functor
aside. “The big guys can use functions with any number of arguments,” he says. “Armed with <$>
and <*>
, I can take any function that expects any number of unpacked arguments. Then I will give her all the packed values ​​and get the same packed result! BVAHAHAHAHAHAHA! " > (*) <$> Just 5 <*> Just 3 Just 15
liftA2
function that does the same thing: > liftA2 (*) (Just 5) (Just 3) Just 15
>>=
(pronounced “binding” ( bind )), which allows to do this.Maybe
- this is a monad:half
be a function that works only with even numbers: half x = if even x then Just (x `div` 2) else Nothing
>>=
to push the packed value through the function. Here's a photo >>=
: > Just 3 >>= half Nothing > Just 4 >>= half Just 2 > Nothing >>= half Nothing
Monad
is another type class. Here is its partial definition: class Monad m where (>>=) :: ma -> (a -> mb) -> mb
>>=
:Maybe
is a monad: instance Monad Maybe where Nothing >>= func = Nothing Just val >>= func = func val
Just 3
!Nothing
to the input, it is still easier: > Just 20 >>= half >>= half >>= half Nothing
Maybe
is Functor
, Applicative
and Monad
in one person.IO
monad:getLine
takes no arguments and gets user data from login: getLine :: IO String
readFile
takes a string (file name) and returns its contents: readFile :: FilePath -> IO String
putStrLn
takes a string and prints it: putStrLn :: String -> IO ()
>>=
! getLine >>= readFile >>= putStrLn
do
notation: foo = do filename <- getLine contents <- readFile filename putStrLn contents
Functor
type class.Applicative
type class.Monad
type class.fmap
or <$>
<*>
or liftA
>>=
or liftM
Source: https://habr.com/ru/post/183150/
All Articles