Add binding section to README

This commit is contained in:
Tristan Hamilton 2020-05-11 13:04:50 +01:00 committed by Michael Bull
parent ff8753321d
commit 7a3e381934
2 changed files with 41 additions and 2 deletions

View File

@ -102,6 +102,40 @@ tokenize(command.toLowerCase())
) )
``` ```
### Binding (Monad Comprehension)
The `binding` keyword allows multiple calls that each return a `Result` to be
chained imperatively. When inside a `binding` block, the `.bind()` function is
accessible on any `Result`. Each call to `bind` will attempt to unwrap the
`Result` and store its value, returning early if any `Result` is an `Err`.
In the example below, should `functionX()` return an `Err`, then execution will
skip both `functionY()` and `functionZ()`, instead storing the `Err` from
`functionX` in the variable named `sum`.
```kotlin
fun functionX(): Result<Int, DomainError> { ... }
fun functionY(): Result<Int, DomainError> { ... }
fun functionZ(): Result<Int, DomainError> { ... }
val sum: Result<Int, ExampleErr> = binding {
val x = functionX().bind()
val y = functionY().bind()
val z = functionZ().bind()
x + y + z
}
println("The sum is $sum") // prints "The sum is Ok(100)"
```
The `binding` keyword primarily draws inspiration from
[Bow's `binding` function][bow-bindings], however below is a list of other
resources on the topic of monad comprehensions.
- [Monad comprehensions - Arrow (Kotlin)][arrow-monad-comprehension]
- [Monad comprehensions - Bow (Swift)][bow-monad-comprehension]
- [For comprehensions - Scala][scala-for-comprehension]
## Inspiration ## Inspiration
Inspiration for this library has been drawn from other languages in which the Inspiration for this library has been drawn from other languages in which the
@ -213,3 +247,8 @@ This project is available under the terms of the ISC license. See the
[customer-42]: https://github.com/michaelbull/kotlin-result/blob/master/example/src/main/kotlin/com/github/michaelbull/result/example/service/InMemoryCustomerRepository.kt#L38 [customer-42]: https://github.com/michaelbull/kotlin-result/blob/master/example/src/main/kotlin/com/github/michaelbull/result/example/service/InMemoryCustomerRepository.kt#L38
[update-customer-error]: https://github.com/michaelbull/kotlin-result/blob/master/example/src/main/kotlin/com/github/michaelbull/result/example/service/CustomerService.kt#L50 [update-customer-error]: https://github.com/michaelbull/kotlin-result/blob/master/example/src/main/kotlin/com/github/michaelbull/result/example/service/CustomerService.kt#L50
[github]: https://github.com/michaelbull/kotlin-result [github]: https://github.com/michaelbull/kotlin-result
[bow-bindings]: https://bow-swift.io/docs/patterns/monad-comprehensions/#bindings
[bow-monad-comprehension]: https://bow-swift.io/docs/patterns/monad-comprehensions
[scala-for-comprehension]: https://docs.scala-lang.org/tour/for-comprehensions.html
[arrow-monad-comprehension]: https://arrow-kt.io/docs/0.10/patterns/monad_comprehensions/
[either-syntax]: https://arrow-kt.io/docs/0.10/apidocs/arrow-core-data/arrow.core/-either/#syntax

View File

@ -8,7 +8,7 @@ import kotlin.contracts.contract
* *
* When inside a [binding] block, the [bind][ResultBinding.bind] function is accessible on any [Result]. Calling the * When inside a [binding] block, the [bind][ResultBinding.bind] function is accessible on any [Result]. Calling the
* [bind][ResultBinding.bind] function will attempt to unwrap the [Result] and locally return its [value][Ok.value]. If * [bind][ResultBinding.bind] function will attempt to unwrap the [Result] and locally return its [value][Ok.value]. If
* the [Result] is an [Err], the binding block will terminate early and return the first [error][Err.error]. * the [Result] is an [Err], the binding block will terminate with that bind and return that failed-to-bind [Err].
* *
* Example: * Example:
* ``` * ```
@ -22,7 +22,7 @@ import kotlin.contracts.contract
* } * }
* ``` * ```
* *
* @sample com.github.michaelbull.result.bind.ResultBindingTest * @sample com.github.michaelbull.result.BindingTest
*/ */
inline fun <V, E> binding(crossinline block: ResultBinding<E>.() -> V): Result<V, E> { inline fun <V, E> binding(crossinline block: ResultBinding<E>.() -> V): Result<V, E> {
contract { contract {