A Monad is any data structure with the follwing two methods:
(>>=) :: m a -> ( a -> m b) -> m b
pure :: a -> m a
the monadic bind is exactly `andThen` in javascript: (>>=) :: m a -> (a -> m b) -> m b
(>>=) :: Future a -> (a -> Future b) -> Future b
Future.andThen :: Future a -> (a -> Future b) -> Future b
and the monadic `pure` is exactly the `Future` constructor: pure :: a -> m a
pure :: a -> Future a
Future.always :: a -> Future a
Every Monad is a Functor, so you also get this one for free: map :: (a -> b ) -> m a -> m b
-- if I know how to convert a's to b's I can convert a future a to a future b
Future.map :: (a -> b) -> Future a -> Future b
So basically, saying "futures are a monad" gives you all the useful functions that you would expect from a future based API, which is nice. It means you can use all kinds of higher level functions not specific to futures to abstract behaviour:Like, given a list of element,s and a way to create a future for each element, create a future that returns a list of elements:
forM :: (Monad m) => Array a -> (a -> m b) -> m (Array b
Future.forEvery :: Array a -> (a -> Future b) -> Future (Array b)Quick glossary:
:: Defines a new function signature. The left hand side is the function name, and the right hand side is the signature.
a -> b A function which converts something of type a to type b
m a A generic m of type a. In Java/C# this might be written as m<a>. eg, `Array String` means an array of string elements, and might be written in C# as Array<String>.
Types starting with a lowercase letter (m, a, b) generally mean the type is generic - as in the function will take any type.It might be helpful to define a function you already know:
string_to_int :: String -> Int
Or, for changing an Array of something to an Array of something else: map :: (a -> b) -> Array a -> Array b
Here, we're defining a function that: 1. Takes a function that converts an 'a' to a 'b' (a -> b)
2. Takes an array of 'a'
3. Returns an array of 'b'
Notice that 'a' and 'b' can be anything! Since the first parameter* is a function that handles the conversion from a to b, the map function actually doesn't need to know what type a and b are.Let's say we pass in the `string_to_int` as the first parameter, now the type checker will actually infer the following function type:
map :: (String -> Int) -> Array String -> Array Int
* Haskell functions actually only ever have one parameter, it uses Currying to accept multiple arguments: https://en.wikipedia.org/wiki/CurryingAlthough in terms of concurrency I've found Elixir/Erlang actor-esque process based system with messaging much more intuitive when building complex programs and much simpler to reason about than the various solutions Haskell offered. But I'm also not an expert at Haskell so take that comparison with a grain of salt.