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

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

package arrow.optics

import arrow.core.Either
import arrow.core.None
import arrow.core.Option
import arrow.core.Some
import arrow.core.flatMap
import arrow.core.getOrElse
import arrow.typeclasses.Monoid
import kotlin.jvm.JvmStatic

/**
 * [OptionalGetter] is a type alias for [POptionalGetter] which fixes the type arguments
 * and restricts the [POptionalGetter] to monomorphic updates.
 */
public typealias OptionalGetter = POptionalGetter

public fun  OptionalGetter(getOption: (source: S) -> Option): OptionalGetter =
  POptionalGetter { s -> getOption(s).toEither { s } }

/**
 * An [OptionalGetter] is an optic that allows into a structure and querying an optional focus.
 *
 * @param S the source of a [POptional]
 * @param T the modified source of a [POptional]
 * @param A the focus of a [POptional]
 */
public interface POptionalGetter: Fold {
  /**
   * Get the focus of an [OptionalGetter] or return the original value while allowing the type to change if it does not match
   */
  public fun getOrModify(source: S): Either

  /**
   * Get the focus of an [OptionalGetter] or `null` if the is not there
   */
  public fun getOrNull(source: S): A? =
    getOrModify(source).getOrNull()

  override fun  foldMap(M: Monoid, source: S, map: (focus: A) -> R): R =
    getOrModify(source).map(map).getOrElse { M.empty() }

  /**
   * Join two [POptionalGetter] with the same focus
   */
  public infix fun  choice(other: POptionalGetter): POptionalGetter, Either, A> =
    POptionalGetter { sources ->
      sources.fold(
        { leftSource ->
          getOrModify(leftSource).mapLeft { Either.Left(it) }
        },
        { rightSource ->
          other.getOrModify(rightSource).mapLeft { Either.Right(it) }
        }
      )
    }

  /**
   * Create a product of the [POptionalGetter] and a type [C]
   */
  public fun  first(): POptionalGetter, Pair, Pair> =
    POptionalGetter { (source, c) -> getOrModify(source).mapLeft { Pair(it, c) }.map { Pair(it, c) } }

  /**
   * Create a product of a type [C] and the [POptionalGetter]
   */
  public fun  second(): POptionalGetter, Pair, Pair> =
    POptionalGetter { (c, s) -> getOrModify(s).mapLeft { c to it }.map { c to it } }

  /**
   * Compose a [POptionalGetter] with a [POptionalGetter]
   */
  public infix fun  compose(other: POptionalGetter): POptionalGetter =
    POptionalGetter { source ->
      getOrModify(source).flatMap { a ->
        other.getOrModify(a)
      }
    }

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

  public companion object {
    /**
     * Invoke operator overload to create an [OptionalGetter] of type `S` with focus `A`.
     */
    public operator fun  invoke(
      getOrModify: (source: S) -> Either
    ): POptionalGetter = object : POptionalGetter {
      override fun getOrModify(source: S): Either = getOrModify(source)
    }

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

    /**
     * [OptionalGetter] to itself if it satisfies the predicate.
     *
     * Select all the elements which satisfy the predicate.
     *
     * ```kotlin
     * import arrow.optics.Traversal
     * import arrow.optics.Optional
     *
     * val positiveNumbers = Traversal.list() compose OptionalGetter.filter { it >= 0 }
     *
     * positiveNumbers.getAll(listOf(1, 2, -3, 4, -5)) == listOf(1, 2, 4)
     * ```
     */
    @JvmStatic
    public fun  filter(predicate: (A) -> Boolean): OptionalGetter =
      OptionalGetter(
        getOption = { if (predicate(it)) Some(it) else None }
      )
  }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy