Java's Optional
is essentially equivalent to Haskell's Maybe
monad, so that's a good starting place for understanding how these "wrapped values" behave.
Functors
, Applicatives
and Monads
are ways of modelling some kind of additional behavior that can modify an existing type. Maybe
takes a type, and modifies it so that it can model both a one single instance or no instance of that type. List
modifies a type so that it models a sequence of instances of the given type.
Each of these typeclasses provides a way to apply a given function to the wrapped type, respecting the modifications that the wrapping type makes. For example, in Haskell,
Functors
Functors use the fmap
or <$>
functions (different names for the same thing):
fmap
or <$>
Functor f => (a -> b) -> f a -> f b
This takes a function and applies to to the wrapped elements
fmap (\x -> x + 1) (Just 1) -- Applies (+1) to the inner value, returning (Just 2)
fmap (\x -> x + 1) Nothing -- Applies (+1) to an empty wrapper, returning Nothing
fmap (\x -> x + 1) [1, 2, 3] -- Applies (+1) to all inner values, returning [2, 3, 4]
(\x -> x + 1) <$> [1, 2, 3] -- Same as above
Applicatives
Applicatives use the <*>
function:
<*>
Applicative f => f (a -> b) -> f a -> f b
This takes a wrapped function and applies it to the wrapped elements
(Just (\x -> x + 1)) <*> (Just 1) -- Returns (Just 2)
(Just (\x -> x + 1)) <*> Nothing -- Returns Nothing
Nothing <*> (Just 1) -- Returns Nothing
[(*2), (*4)] <*> [1, 2] -- Returns [2, 4, 4, 8]
Monads
There are two relevant functions in the Monad typeclass:
return
Monad m => a -> m a
(>>=)
Monad m => m a -> (a -> m b) -> m b
(pronounced "bind")
The return
function bears no resemblance to the one you may be familiar with in C-style languages. It takes a raw, unwrapped value, and wraps it up in the desired monadic type.
makeJust :: a -> Maybe a
makeJust x = return x
let foo = makeJust 10 -- returns (Just 10)
The bind function lets you temporarily unwrap the inner elements of a Monad and pass them to a function that performs some action that wraps them back UP in the same monad. This can be used with the return
function in trivial cases:
[1, 2, 3, 4] >>= (\x -> return (x + 1)) -- Returns [2, 3, 4, 5]
(Just 1) >>= (\x -> return (x + 1)) -- Returns (Just 2)
Nothing >>= (\x -> return (x + 1)) -- Returns Nothing
Where it gets interesting is when you have functions to chain together that don't require you to use return
. I like to use getLine
and putStrLn
as examples, which have the following signatures using the IO
monad:
getLine
IO String
putStrLn
String -> IO ()
You can call these functions like so:
getLine >>= (\x -> putStrLn x) -- Gets a line from IO and prints it to the console
getLine >>= putStrLn -- With currying, this is the same as above
You could also use the >>=
function to chain a few operations together.
-- Reads a line from IO, converts to a number, adds 10 and prints it
getLine >>= (return . read) >>= (return . (+10)) >>= putStrLn . show
Optional
in Java is one such example of a "wrapper". What a wrapper (like a Functor) is, is more or less explained in the article you linked to.