Haskell – Purpose of Wrapped Values in Haskell

haskellmonad

I've recently read an article about Functors, Applicatives and Monads in Haskell and it concludes with these statements:

  • functors: you apply a function to a wrapped value using fmap or <$>
  • applicatives: you apply a wrapped function to a wrapped value using <*> or liftA
  • monads: you apply a function that returns a wrapped value, to a wrapped value using >>= or liftM

This is all clear but I don't get what the purpose of the a wrapped value is. Do they work like the decorators in python or the Optional in java? I would greatly appreciate some practical example from the real world.

Best Answer

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