Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arrow Fx docs editorial review #1290

Merged
merged 5 commits into from
Feb 10, 2019
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
polymorphism readme edits
  • Loading branch information
MaureenElsberry committed Feb 6, 2019
commit b53951fc71eb0cb4c2f607c14016b6f06e3b4db4
65 changes: 32 additions & 33 deletions modules/docs/arrow-docs/docs/docs/effects/fx/polymorphism/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ Fx programs can be declared in a polymorphic style and made concrete to your fra

## Creating polymorphic programs

So far all programs we've created in previous examples where built with `Arrow`'s `IO`.
Fx is not restricted to `IO`. Since `IO` provides extensions for `Concurrent<F>` we can also create extensions for the `fx` DSL directly as in all previous examples.
So far, the programs we've created in previous examples were built with `Arrow`'s `IO`, but Fx is not restricted to `IO`. Since `IO` provides extensions for `Concurrent<F>`, we can also create extensions for the `fx` DSL directly as in all previous examples.

We can also code against `Fx` assuming it would be provided at some point in the future.

In the following example the program is declared polymorphic and then made concrete to Arrow IO at the edge.
In the following example, the program is declared polymorphic and then made concrete to Arrow IO at the edge.

```kotlin:ank:playground
import arrow.effects.IO
Expand Down Expand Up @@ -49,19 +48,19 @@ fun main() =

Polymorphism is important for two main reasons: *Correctness* & *Flexibility*.

Polymorphic programs are more likely to be correct because the API's available to them is constrained by the functionality described in the type classes that are used as scope, in the previous example the receiver of the function.
What's most amazing about this technique is that as we declare our programs only data types that are able to provide extensions for `Fx` and `UnsafeRun` are able to be provided as arguments to the final `main`.
You will not be able to compile this program unless your data type supported those extensions.
Polymorphic programs are more likely to be correct because the APIs available to them are constrained by the functionality described in the type classes that are used as a scope. In the previous example, this is the receiver of the function.
What's most amazing about this technique is that, as we declare our programs, only data types that can provide extensions for `Fx` and `UnsafeRun` are able to be provided as arguments to the final `main`.
You will not be able to compile this program unless your data type supports those extensions.

Polymorphic programs are more flexible that their concrete counterparts because they can run unmodified in multiple runtimes.
In the same way `main` is concrete in the previous example to `IO`, we could have used there instead Rx2 Observables, Reactor Flux or any other data type that is able to provide extensions for `Fx` and `UnsafeRun`.
Polymorphic programs are more flexible than their concrete counterparts because they can run unmodified in multiple runtimes.
In the same fashion that `main` is concrete in the previous example to `IO`, we could have used Rx2 Observables, Reactor Flux, or any other data type that is able to provide extensions for `Fx` and `UnsafeRun` instead.
See [Issue 1281](https://github.com/arrow-kt/arrow/issues/1281) which tracks support for those frameworks or reach out to us if you are interested in support for any other framework.

## Fx for all data types

Fx is not restricted to data types that support concurrency like `IO`. Other data types can utilize versions of the `Fx` dsl with reduced powers based on the level of constrains that they can provide extensions for.
Fx is not restricted to data types that support concurrency like `IO`. Other data types can utilize versions of the `Fx` DSL with reduced powers based on the level of constrains that they can provide extensions for.

The Arrow library already provides the ability to compute imperatively over all monads and brings first class do notation / comprehensions with an extremely elegant syntax thanks to Kotlin's operator overloading features and suspension system. The following examples demonstrate use of effect binding in two of the many possible data types in which `Fx` programs can compile to.
The Arrow library already provides the ability to compute imperatively over all monads and brings first-class do-notation / comprehensions with an extremely elegant syntax thanks to Kotlin's operator overloading features and suspension system. The following examples demonstrate the use of effect binding with two of the many options of data types in which `Fx` programs can compile to.

*Fx over `Option`*
```kotlin:ank:playground
Expand Down Expand Up @@ -101,51 +100,51 @@ fun main() {
}
```

The `component1` operator over all `Kind<F, A>` is able to obtain a non blocking `A` bound in the LHS in the same way `!` does.
The `component1` operator over all `Kind<F, A>` is able to obtain a non-blocking `A` bound in the LHS in the same way `!` does.

```kotlin
suspend fun <A> Kind<F, A>.bind(): A
suspend operator fun <A> Kind<F, A>.component1(): A = bind()
suspend operator fun <A> Kind<F, A>.not(): A = bind()
```

The result is destructuring syntax for all monadic expressions by receiving the value bound in the left hand side in a non blocking fashion.
The result destructures syntax for all monadic expressions by receiving the value bound in the left-hand side in a non-blocking fashion.

## Arrow Fx vs Tagless Final

Arrow Fx eliminates the need for tagless style algebras and parametrization over expressions that require `F` as a type parameter when invoking functions.

When modeling effects as `suspend` functions that are disallowed to compile in the pure environment but welcome in compositional blocks denoted as `effect { sideEffect() }`.
When modeling effects as `suspend`, functions that are disallowed to compile in the pure environment but welcome in compositional blocks denoted as `effect { sideEffect() }`.

Arrow Fx brings first class, no-compromises direct style syntax for effectful programs that are constrained by monads that can provide an extension of `Concurrent<F>`.
It models effects with the Kotlin Compiler native system support for `suspend` functions and abilities to declare restricted suspended blocks with `@RestrictsSuspension` in which effects are allowed to run and compose.
Arrow Fx brings first class, no-compromises, direct style syntax for effectful programs that are constrained by monads that can provide an extension of `Concurrent<F>`.
It models effects with the Kotlin Compiler's native system support for `suspend` functions and the ability to declare restricted suspended blocks with `@RestrictsSuspension` in which effects are allowed to run and compose.

We still preserve `F` to achieve polymorphism but it's usage it's restricted to type declarations and unnecessary in program composition.
We still preserve `F` to achieve polymorphism, but its usage is restricted to type declarations and unnecessary in program composition.

As a consequence of the assimilation and elimination of the `F` type parameter from the syntax in such programs the entire hierarchy of type class combinators we find in `Functor`, `Applicative` and `Monad` dissapear and what they model is swallowed as syntax that operates directly over the environment.
As a consequence of the assimilation and elimination of the `F` type parameter from the syntax in such programs, the entire hierarchy of type class combinators we find in `Functor`, `Applicative`, and `Monad` disappear and what they model is swallowed as syntax that operates directly over the environment.

This simplification is manifested in the world of suspended effects in the fact that all values of type `Kind<F, A>` can bind to `A` in the left hand side in a non blocking fashion because Kotlin supports imperative CPS and continuation styles syntactically.
This simplification is manifested in the world of suspended effects in the fact that all values of type `Kind<F, A>` can bind to `A` in the left-hand side in a non-blocking fashion because Kotlin supports imperative CPS and continuation styles syntactically.
Arrow Fx uses the Kotlin compiler native support for implicit CPS to achieve direct syntax for effectful monads.

This has a tremendous impact in program declaration since all the functional combinators where before you had as return type a `Kind<F, A>` can be easily applied with `!` to obtain a non blocking value.
`map`, `flatMap` are no longer necessary because their returned values are flattened and automatically bound in the monad context when you use `!`
This has a tremendous impact on program declaration since all the functional combinators can be easily applied with `!` to obtain a non blocking value, where before you had `Kind,F, A>` as a return type.
`map` and `flatMap` are no longer necessary because their returned values are flattened and automatically bound in the monad context when you use `!`.

This leads us to realize that there is a some direct relationship between `suspend () -> A` and `Kind<F, A>` or what in Scala is `F[A]`.
This leads us to the realization that there is a direct relationship between `suspend () -> A` and `Kind<F, A>`, or, what `F[A]` is in Scala.
This relationship establishes that a `suspend` function denoting an effect can be deferred and controlled by the monadic context of a suspend capable data type.

`effect` takes us without blocking semantics from a suspended function to any `Kind<F, A>`.
`effect` takes us, without blocking semantics, from a suspended function to any `Kind<F, A>`.
This includes IO and pretty much everything you are using today in a tagless final or IO wrapping style.

This relationship also eliminates the need to ever use any of the functional combinators you find in the `Functor<F>` hierarchy for effectful monads.
All of them are swallowed by equivalent direct syntax in the environment as demonstrated in the examples below:
This relationship also eliminates the need for using any of the functional combinators you find in the `Functor<F>` hierarchy for effectful monads.
These are all swallowed by equivalent direct syntax in the environment as demonstrated in the examples below:

### Good bye `Functor`, `Applicative` and `Monad`

`Arrow Fx` removes the need to use the functional combinators found in the Functor, Applicative and Monad type classes.
`Arrow Fx` removes the need to use the functional combinators found in the Functor, Applicative, and Monad type classes.

These combinators are instead represented as direct syntax and compile-time guaranteed by the Kotlin compiler that effectful computations denoted by the user can't run uncontrolled in functions denoted as pure.
These combinators are instead represented as direct syntax and compile-time and guaranteed by the Kotlin compiler that effectful computations denoted by the user can't run uncontrolled in functions denoted as pure.

The following combinators illustrate how the Functor hierarchy functions are pointless in the environment given we can declare programs that respect the same semantics thanks to the Kotlin suspension system. These below are examples of a few of the most well known combinators that would disappear from your day to day FP programming and what they look like in Arrow Fx:
The following combinators illustrate how the Functor hierarchy functions are pointless in the environment given we can declare programs that respect the same semantics thanks to the Kotlin suspension system. Below, we'll see examples of a few of the most well-known combinators that will disappear from your day-to-day FP programming and what they look like in Arrow Fx:

| TypeClass | Wrapped | Fx |
|---------------------|-----------|--------------------|
Expand All @@ -158,10 +157,10 @@ The following combinators illustrate how the Functor hierarchy functions are poi
| MonadDefer.delay | `IO.delay { 1 }` | `effect { 1 }` |
| MonadDefer.defer | `IO.defer { IO { 1 } }` | `effect { 1 }` |

This is in general true for effectful data types that are non-commutative.
Note that implicit CPS style with non-blocking direct binding has the disadvantage that for non-commutative monads where the order of effects matter you can't apply substitution based on referential transparency.
This is, in general, true for effectful data types that are non-commutative.
Note that implicit CPS style with non-blocking direct binding has a disadvantage. You cannot apply substitution based on referential transparency for non-commutative monads where the order of effects matter.

Arrow Fx is aware of this but still allows users to use `fx` on non-commutative monads such as `List` providing safe `fx` builders that guarantee suspended effects are applied in order in different arguments before they are composed.
Arrow Fx is aware of this but still allows users to use `fx` on non-commutative monads such as `List`, providing safe `fx` builders that guarantee suspended effects are applied in order in different arguments before they are composed.
Altering the order of effect when using the safe builders for non-commutative monads does not alter the results because it enforces effect order prior to composition.

```kotlin:ank:playground
Expand All @@ -180,8 +179,8 @@ fun main() {
}
```

Arrow identifies non-blocking binding in these non-commutative monads as unsafe and an as an effect worth tracking!.
For consistency if you want to shoot yourself in the foot, performing free environmental effect application for these non-commutative types requires the user to give explicit permission to activate the unsafe `fx` block.
Arrow identifies non-blocking binding in these non-commutative monads as unsafe and as an effect worth tracking!
For consistency, if you want to shoot yourself in the foot, performing free environmental effect application for these non-commutative types requires the user to give explicit permission to activate the unsafe `fx` block.

```kotlin:ank:playground
import arrow.unsafe
Expand Down Expand Up @@ -213,7 +212,7 @@ fun main() {

The previous program shows how applying substitution alters the order of effects and affects the outcome.

The same program expressed in a commutative monad which is the case of `IO` shows how both programs yield the same deterministic result even after changing the order of effects:
The same program expressed in a commutative monad which is the case of `IO`, shows how both programs yield the same deterministic result even after changing the order of effects:

```kotlin:ank:playground
import arrow.effects.IO
Expand Down