There are similar questions here but they are attached to a particular programming language and I am looking for an answer on the conceptual level.
As I understand, Functors are essentially immutable containers that expose map() API which derives another functor. Which addition makes it possible to call a particular functor a monad?
As I understand, every monad is a functor but not every functor is a monad.
A functor is a data type that implements the Functor typeclass. An applicative is a data type that implements the Applicative typeclass. A monad is a data type that implements the Monad typeclass. A Maybe implements all three, so it is a functor, an applicative, and a monad.
In functional programming, a functor is a design pattern inspired by the definition from category theory, that allows for a generic type to apply a function inside without changing the structure of the generic type.
A function assigns to every element of a set X an element of a set Y. A functor assigns to every object of a category C an object of a category D and also assigns to every morphism in C a morphism in D in a way compatible with sources, targets, and composition.
A Functor is a ubiquitous type class involving types that have one "hole", i.e. types which have the shape F[*] , such as Option , List and Future . (This is in contrast to a type like Int which has no hole, or Tuple2 which has two holes ( Tuple2[*,*] )).
Let me explain my understanding without going into category theory:
Functors and monads both provide some tool to wrapped input, returning a wrapped output.
Functor = unit + map (i.e. the tool)
where,
unit
= something which takes raw input and wraps it inside a small context.
map
= the tool which takes a function as input, applies it to raw value in wrapper, and returns wrapped result.
Example: Let us define a function which doubles an integer
// doubleMe :: Int a -> Int b const doubleMe = a => 2 * a; Maybe(2).map(doubleMe) // Maybe(4)
Monad = unit + flatMap (or bind or chain)
flatMap
= the tool which flattens the map
, as its name implies. It will be clear soon with the example below.
Example: Let us say we have a curried function which appends two strings only if both are not blank.
Let me define one as below:
append :: (string a,string b) -> Maybe(string c)
Let's now see the problem with map
(the tool that comes with Functor
),
Maybe("a").map(append("b")) // Maybe(Maybe("ab"))
How come there are two Maybe
s here?
Well, that's what map
does; it applies the provided function to the wrapped value and wraps the result.
Let's break this into steps,
Apply the mapped function to the wrapped value ; here the mapped function is append("b")
and the wrapped value is "a"
, which results in Maybe("ab")
.
Wrap the result, which returns Maybe(Maybe("ab"))
.
Now the value we are interested in is wrapped twice. Here comes flatMap
to the rescue.
Maybe("a").flatMap(append("b")) // Maybe("ab")
Of course, functors and monads have to follow some other laws too, but I believe this is not in the scope of what is asked.
(Note that this will be a simplified explanation for category theory concepts)
A Functor is a function from a set of values a to another set of values: a -> b
. For a programming language this could be a function that goes from String -> Integer
:
function fn(text: string) : integer
Composition is when you use the value of one function as input to the value of the next: fa(fb(x))
. For example:
hash(lowercase(text))
A Monad allows to compose Functors that either are not composable otherwise, compose Functors by adding extra functionality in the composition, or both.
An example of the first is a Monad for a Functor String -> (String, Integer)
An example of the second is a Monad that counts the Number of functions called on a value
A Monad includes a Functor T
that is responsible for the functionality you want plus two other functions:
input -> T(input)
T(T(input)) -> T(input)
The first function allows to transform your input values to a set of values that our Monad can compose. The second function allows for the composition.
So in conclusion, every Monad is not a Functor but uses a Functor to complete it's purpose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With