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!

Datatypes in Arrow

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.

General use
  • 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

Error handling
  • Validated - returns the result of aggregating multiple calculations that can fail, and it also aggregates the errors
  • Kleisli - 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



  • [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

Recursion schemes are an abstraction for structured recursion that ensure runtime safety and provide powerful abstractions for recursive datatypes.

  • Fix - Models birecursion

  • Mu - Models recursion

  • Nu - Models corecursion

Do you like Arrow?

Arrow Org