A datatype is a an abstraction that encapsulates one reusable coding pattern. These solutions have a canonical implementation that is generalized for all possible uses.
A datatype is implemented by a data class, or a sealed hierarchy of data classes and objects.
These datatypes are generalized by having one or several generic parameters,
and, to become a type constructor, they implement the interface Kind
for these generic parameters.
Datatypes work over themselves, never directly over the values defined by its generic parameters.
Option<A>
is a datatype that represents absence.
It has one generic parameter A
, representing the type of the values that Option
may contain.
Option
can be specialized for any type A
because this type does not affect its behavior.
Option
behaves the same for Int
, String
, or DomainUserClass
.
To indicate that Option
is a type constructor for all values of A
, it implements OptionOf<A>
, which is a typealias of Kind<ForOption, A>
.
The implementation of Option<A>
is a sealed class with two subtypes: An object None
and a data class Some<A>
.
Some<A>
represents presence of the value and thus it has one field containing it, and None
represents absence.
All operations over Option
have to take into account absence or presence,
so there is a function fold()
that takes a continuation function per case, () -> B
and (A) -> B
.
The implementation of fold()
is a simple when
that checks whether this
is a None
or a Some<A>
, and it applies the appropriate continuation function.
All other functions provided by Option
are implemented by using fold()
, making for idiomatic helper functions like getOrNull
, getOrElse
, or map
. These functions work for any value of A
and B
. This way, what Option
does for each individual case of String
, Int
, or absence is up to the functions passed by the user.
Feel free to explore the implementation of Option
and other datatypes to discover their behavior!
We will list all the datatypes available in Arrow by the module they belong to, and a short description of the coding pattern they abstract.
Core contains the datatypes that are also used by the public API of several typeclasses, so they are always required.
Id
- a simple wrapper without any behavior, used mostly for testing
Option
- absence of a value, or failure to construct a correct value
Either
- an if/else branch in execution
Eval
- lazy evaluation of functions with stack safety and memoization
TupleN
- a heterogeneous grouping of 2-9 values without creating a named class
Data contains the bulk of the datatypes provided by Arrow. We can separate them into several categories.
NonEmptyList
- a homogeneous list that has at least 1 value
Ior
- a branch in execution for three possible paths: One, two, or both
Const
- tags a value with a “phantom generic” that’s never instantiated, and it can be used for example to represents units or state
Validated
- returns the result of aggregating multiple calculations that can fail, and it also aggregates the errorsKleisli
- similar to Dependency Injection and Inversion of Control, it represents a calculation with a dependency on an external context
Reader
- same as kleisli but operating over the Id
datatype
Writer
- represents calculations that carry over one extra aggregated value, generally a logger or reporter
State
- represents a stateful calculation with a carried value that can be read from or modified, like a combination of reader and writer
These types wrap over some of Kotlin’s collections and functions to give them capabilities related to typeclasses provided by Arrow.
A transformer is a special kind of datatype that allows combining two datatypes to give one of them the abstractions of another
OptionT
- gives the datatype wrapped the properties of Option
EitherT
- gives the datatype wrapped the properties of Either
ReaderT
- gives the datatype wrapped the properties of Reader
WriterT
- gives the datatype wrapped the properties of Writer
StateT
- gives the datatype wrapped the properties of State
TODO
[Cokleisli
]
[Coreader
]
Store
- a datatype that holds an initial state and a function for extracting a representation of it.
Moore
- a datatype that holds an initial state and can move to new states only when an event of a specific type is dispatched.
Sum
- a datatype that holds two comonads and a flag for indicating which one is active. Both sides evolve at the same time.
Day
- a datatype that holds two comonads which evolve independently.
All effects are different implementations of the same abstraction: Lazy execution of code that can move to other threads and cause exceptions. They are more general than the other datatypes as they combine the abstractions of several of them.
Free is a general abstraction to represent Domain Specific Languages that can be interpreted using Effects.
Recursion schemes are an abstraction for structured recursion that ensure runtime safety and provide powerful abstractions for recursive datatypes.
Do you like Arrow?
✖