Comment

Comment by chombier

A functor is two things:

- a parametrized type, like for instance List: you can have lists of integers, floats, functions, or any other type

- a way of mapping (in the sense of List.map) between instances of the parametrized type, given regular functions. This mapping should behave nicely with respect to regular function composition.

If your parametrized type is F, then the mapping operation turns ("lifts") regular functions A -> B into functions (F A) -> (F B) in a reasonable way: "if you give me a function then I can transform any list using it".

Functors can be used to "decorate" values: you can model exceptions (some value or an error), promises (some value not yet computed), state (some value + side effects) and many other kinds of effects using functors.

So in general an effectful computation will have type A -> (F B) for some functor F modeling the effect. And now you have a problem: how to compose effectful computations in order to build larger programs out of smaller ones? You cannot simply compose A -> (F B) with B -> (F C) since the types don't match.

What you need is a way of transforming an effectful computation B -> (F C) into a lifted function (F B) -> (F C) so that you can compose A -> (F B) with (F B) -> (F C) in order to get A -> (F C).

That device should satisfy some properties to make effectful composition work the way you expect (in particular there should exist identity effectful computations), and is called a monad.

A monad is a functor + some extra operations (bind/return) satisfying properties that will make effectful computations (using this functor) composable.

The type of bind is generally written (F A) -> (A -> F B) -> (F B) but really it is the same as (A -> F B) -> (F A -> F B) above (takes an effectful computation, gives back a lifted function).

parent chombier 5 years ago

Discussion

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton