All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.arrow.optics.Getter.kt Maven / Gradle / Ivy

There is a newer version: 2.0.1-alpha.1
Show newest version
package arrow.optics

import arrow.core.Either
import arrow.core.compose
import arrow.core.identity
import arrow.typeclasses.Monoid

/**
 * A [Getter] is an optic that allows to see into a structure and getting a focus.
 *
 * A [Getter] can be seen as a get function:
 * - `get: (S) -> A` meaning we can look into an `S` and get an `A`
 *
 * @param S the source of a [Getter]
 * @param A the focus of a [Getter]
 */
public fun interface Getter : Fold {

  /**
   * Get the focus of a [Getter]
   */
  public fun get(source: S): A

  override fun  foldMap(M: Monoid, source: S, map: (focus: A) -> R): R =
    map(get(source))

  /**
   * Create a product of the [Getter] and a type [C]
   */
  public fun  first(): Getter, Pair> =
    Getter { (s, c) -> get(s) to c }

  /**
   * Create a product of type [C] and the [Getter]
   */
  public fun  second(): Getter, Pair> =
    Getter { (c, s) -> c to get(s) }

  /**
   * Create a sum of the [Getter] and type [C]
   */
  override fun  left(): Getter, Either> =
    Getter { sc -> sc.mapLeft(this::get) }

  /**
   * Create a sum of type [C] and the [Getter]
   */
  override fun  right(): Getter, Either> =
    Getter { cs -> cs.map(this::get) }

  /**
   * Join two [Getter] with the same focus
   */
  public infix fun  choice(other: Getter): Getter, A> =
    Getter { s -> s.fold(this::get, other::get) }

  /**
   * Pair two disjoint [Getter]
   */
  public infix fun  split(other: Getter): Getter, Pair> =
    Getter { (s, c) -> get(s) to other.get(c) }

  /**
   * Zip two [Getter] optics with the same source [S]
   */
  public infix fun  zip(other: Getter): Getter> =
    Getter { s -> get(s) to other.get(s) }

  /**
   * Compose a [Getter] with a [Getter]
   */
  public infix fun  compose(other: Getter): Getter =
    Getter(other::get compose this::get)

  public operator fun  plus(other: Getter): Getter =
    this compose other

  public companion object {

    public fun  id(): Getter =
      PIso.id()

    /**
     * [Getter] that takes either [S] or [S] and strips the choice of [S].
     */
    public fun  codiagonal(): Getter, S> =
      Getter { aa -> aa.fold(::identity, ::identity) }
  }
}