Monad
is a typeclass that abstracts over sequential execution of code.
This doc focuses on the methods provided by the typeclass.
If you’d like a long explanation of its origins with simple examples with nullable, Option
, and List
,
head to The Monad Tutorial.
Monad
includes all combinators present in Applicative
and Selective
.
Takes a continuation function from the value A
to a new Kind<F, B>
, and returns a Kind<F, B>
.
Internally, flatMap
unwraps the value inside the Kind<F, A>
and applies the function to obtain the new Kind<F, B>
.
Because Kind<F, B>
cannot be created until A
is unwrapped, it means that one cannot exists until the other has been executed, effectively making them a sequential chain of execution.
import arrow.core.*
import arrow.core.extensions.*
import arrow.fx.*
Some(1).flatMap { a ->
Some(a + 1)
}
// Option.Some(2)
The improvement of flatMap
over regular function composition is that flatMap
understands sealed datatypes, and allows for short-circuiting execution.
None.flatMap { a: Int ->
Some(a + 1)
}
// Option.None
Right(1).flatMap { _ ->
Left("Error")
}.flatMap { b: Int ->
Right(b + 1)
}
// Either.Left(Error)
Note that, depending on the implementation of Kind<F, A>
, this chaining function may be executed immediately, i.e., for Option
or Either
;
or lazily, i.e., suspend
or Flow
.
Combines two nested elements into one Kind<F, A>
.
import arrow.core.extensions.option.monad.flatten
Some(Some(1)).flatten()
// Option.Some(1)
Some(None).flatten()
// Option.None
Like flatMap
, but it combines the two sequential elements in a Tuple2
.
import arrow.core.extensions.option.monad.mproduct
Some(5).mproduct {
Some(it * 11)
}
// Option.Some((5, 55))
Sequentially executes two elements that are independent from one another.
The Eval
variant allows you to pass lazily calculated values.
import arrow.core.extensions.option.monad.followedBy
Some(1).followedBy(Some(2))
// Option.Some(2)
Sequentially executes two elements and ignores the result of the second. This is useful for effects like logging.
import arrow.core.extensions.option.monad.flatTap
fun logValue(i: Int): Option<Unit> = Some(println(i))
Some(1).flatTap(::logValue)
// Option.Some(1)
Sequentially executes two elements that are independent from one another, ignoring the value of the second one.
The Eval
variant allows you to pass lazily calculated values.
import arrow.core.extensions.option.monad.*
Some(1).productL(Some(2))
// Option.Some(1)
Arrow provides MonadLaws
in the form of test cases for internal verification of lawful instances and third party apps creating their own Monad instances.
Monad
instancesArrow already provides Monad
instances for most common datatypes both in Arrow and the Kotlin stdlib.
See Deriving and creating custom typeclass to provide your own Monad
instances for custom datatypes.
Do you like Arrow?
✖