package com.github.michaelbull.result /** * Accumulates value starting with [initial] value and applying [operation] from left to right to * current accumulator value and each element. * * @param initial The value to start with. * @param operation The operation to apply to each element and current accumulator value. */ inline fun Iterable.fold( initial: R, operation: (acc: R, T) -> Result ): Result { var accumulator = initial forEach { element -> val operationResult = operation(accumulator, element) when (operationResult) { is Ok -> { accumulator = operationResult.value } is Error -> return err(operationResult.error) } } return ok(accumulator) } /** * Accumulates value starting with [initial] value and applying [operation] from right to left to * each element and current accumulator value. * * @param initial The value to start with. * @param operation The operation to apply to each element and current accumulator value. */ inline fun List.foldRight( initial: R, operation: (T, acc: R) -> Result ): Result { var accumulator = initial if (!isEmpty()) { val iterator = listIterator(size) while (iterator.hasPrevious()) { val operationResult = operation(iterator.previous(), accumulator) when (operationResult) { is Ok -> { accumulator = operationResult.value } is Error -> return err(operationResult.error) } } } return ok(accumulator) } /** * Combine a vararg of [Results][Result] into a single [Result] (holding a [List]). * * - Elm: [Result.Extra.combine](http://package.elm-lang.org/packages/circuithub/elm-result-extra/1.4.0/Result-Extra#combine) * * @param results The [Results][Result] to combine. * @return The combined [Result]. */ fun combine(vararg results: Result) = results.asIterable().combine() /** * Combine an [Iterable] of [Results][Result] into a single [Result] (holding a [List]). * * - Elm: [Result.Extra.combine](http://package.elm-lang.org/packages/circuithub/elm-result-extra/1.4.0/Result-Extra#combine) * * @return The combined [Result]. */ fun Iterable>.combine(): Result, E> { return ok(map { when (it) { is Ok -> it.value is Error -> return err(it.error) } }) } /** * Extracts from a vararg of [Results][Result] all the [Ok] elements. All the [Ok] elements are * extracted in order. * * - Haskell: [Data.Either.lefts](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:lefts) * * @param results The [Results][Result] from which to extract [Ok] elements. * @return The extracted [Ok] elements. */ fun getAll(vararg results: Result) = results.asIterable().getAll() /** * Extracts from an [Iterable] of [Results][Result] all the [Ok] elements. All the [Ok] elements * are extracted in order. * * - Haskell: [Data.Either.lefts](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:lefts) * * @return The extracted [Ok] elements. */ fun Iterable>.getAll(): List { return filter { it is Ok }.map { (it as Ok).value } } /** * Extracts from a vararg of [Results][Result] all the [Error] elements. All the [Error] elements * are extracted in order. * * - Haskell: [Data.Either.rights](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:rights) * * @param results The [Results][Result] from which to extract [Error] elements. * @return The extracted [Error] elements. */ fun getAllErrors(vararg results: Result) = results.asIterable().getAllErrors() /** * Extracts from an [Iterable] of [Results][Result] all the [Error] elements. All the [Error] * elements are extracted in order. * * - Haskell: [Data.Either.rights](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:rights) * * @return The extracted [Error] elements. */ fun Iterable>.getAllErrors(): List { return filter { it is Error }.map { (it as Error).error } } /** * Partitions a vararg of [Results][Result] into a [Pair] of [Lists][List]. All the [Ok] elements * are extracted, in order, to the [first][Pair.first] value. Similarly the [Error] elements are * extracted to the [Pair.second] value. * * - Haskell: [Data.Either.partitionEithers](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:partitionEithers) * * @param results The [Results][Result] to partition. * @return A [Pair] of [Lists][List] where the [first][Pair.first] value * contains the [Ok] elements and the [second][Pair.second] value contains the [Error] elements. */ fun partition(vararg results: Result) = results.asIterable().partition() /** * Partitions an [Iterable] of [Results][Result] into a [Pair] of [Lists][List]. All the [Ok] * elements are extracted, in order, to the [first][Pair.first] value. Similarly the [Error] * elements are extracted to the [Pair.second] value. * * - Haskell: [Data.Either.partitionEithers](https://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Either.html#v:partitionEithers) * * @return A [Pair] of [Lists][List] where the [first][Pair.first] value * contains the [Ok] elements and the [second][Pair.second] value contains the [Error] elements. */ fun Iterable>.partition(): Pair, List> { val values = mutableListOf() val errors = mutableListOf() forEach { result -> when (result) { is Ok -> values.add(result.value) is Error -> errors.add(result.error) } } return Pair(values, errors) }