6

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.

  • Yes, 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. – Andres F. Nov 24 '15 at 19:15
8

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
  • What you describe has some resemblance to python decorators or the decorator pattern in java but this seems more elegant to me since the Nothing is implicitly checked and no boilerplate is needed. Right? – Adam Arold Nov 24 '15 at 19:49
  • 2
    @AdamArold They're not totally dissimilar. It's hard to properly describe how things like Monads work because they work on a very abstract and generic level, and can have any number of very different uses. They basically just do "something" to change how a type behaves, without having to know anything specific about the type that they're working on. – KChaloux Nov 24 '15 at 19:54
  • I think I get what you are trying to say. So the difference to say a java decorator is that this is a more abstract decorator where I get an Object and I can do whatever I want with that Object which can be even a FunctionalInterface or such. – Adam Arold Nov 24 '15 at 20:00
  • 2
    @AdamArold Keeping in mind that in Haskell, you don't have a base Object type. Haskell's brand of polymorphism is mostly via Parametric Polymorphism (equivalent to Generics in Java). This means that you don't have to lose type information (by casting to something more general like Object) when wrapping up a type in a Monad. In fact, Monads can't be properly represented in Java, because they require Higher Kinded Types - a generic type whose definition includes another generic type. Hence the (Monad m) => m a you see up there. Both m and a are generic. – KChaloux Nov 24 '15 at 20:42
  • 2
    Might be worth adding that the value of Applicative is that you can apply functions of multiple arguments, e.g., ((\x y z -> x + y + z) <$> Just 5 <*> Just 10 <*> Just 200) == Just 215. Also, in x >>= y, the result of y can depend on the result of x, so they must be evaluated serially; whereas with x <*> y, the two are independent and can be evaluated concurrently, e.g., with the Concurrently applicative. – Jon Purdy Nov 25 '15 at 23:35
3

That article has the virtue of being very visual and intuitive... but at the cost of building intuitions that are often false. The concepts of functor, applicative and monad do not require you to have "wrapped" values, strictly speaking.

One good example to consider here is the concept of promises that's been gaining traction recently (particularly in Javascript). A promise, in this sense, is an object that acts as a placeholder for the result value of an asynchronous, background computation, like fetching some data from a remote service. In addition to that, it serves as a mediator between the asynchronous computation and functions that need to operate on its anticipated result.

Promise libraries usually support a functorial/monadic API where you can "chain" a function onto a promise, which produces another promise that produces the result of applying that function to the original promise's result.

This provides a vivid example of the value of the functor/monad interface, because the whole point of promises is that they allow you to say what function should apply to the result of a background task, before that task has completed. When you map a function over a promise, the value that your function should apply to may not have been computed yet (and in fact, if there is an error somewhere it may never be computed).

More generally, you can think of functor/applicative/monad as interfaces for mediator objects that sit in between functions and arguments, and connect them indirectly according to some policy. The simplest way to use a function is just to call it with some arguments; but if you have first-class functions, you have other, indirect options—you can supply the function to a mediator object that will control if, when and how many times the function will be called, and what to do with its result. Promises are one such example:

  1. They call the functions supplied to them when the result of some background task is completed
  2. The results of those functions are then handed over to other promises that are waiting for them.
2

Well Optional is a monad (and therfore an applicative functor and a functor), and indeed many container types are monadic as well, and people usually have a fairly good intuition for how containery type things work as these things, as I believe you do from your question.

However lots of things that aren't normally thought of as containers can also be monads, applicative or functors e.g. parsers combinators or IO or writing to a log. An alternative way of looking at them is as computations in some context, for instance, while List is obviously a container of values you can also consider computations in the List monad as representing nondeterministic computations

What I'm leading up to here is that monads are intrinsictly more abstract than the examples you are after. they are literally:

  • a type constructor
  • a return/unit function
  • and a bind (or join and fmap) function

that satisfy the 3 monad laws, there is no further unifying principle than that (for a monad, replace with relevant functions and laws for Applicative and Functor)

  • So what is the difference between a monad and a decorator then? – Adam Arold Nov 24 '15 at 19:52
  • at the very least i'd think the static/dynamic divide is a difference between them, but I don't know enough python to know if there are any other implications – jk. Nov 24 '15 at 20:01
  • on the Java side, as I said Optional in a monad but as a pattern only, Java lacks the power in its type system to write a function that can operate on any monad – jk. Nov 24 '15 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.