Skip to content

Commit

Permalink
Improve docs to better explain monads (#956)
Browse files Browse the repository at this point in the history
* Redo intro to typeclasses to embed better on glossary

* Rephrase comprehensions to explain things before introducing Monad

* Add Monad docs

* First pass at the mword tutorial

* Translate snippets

* Some tweaks here and there

* Add menu entry

* Add linkback to mword from comprehensions

* Proper brackets

* Fix Future class

* Fix flatMap

* Fix casing

* Add new section on typeclasses. Rename folder to monads

* Wording

* Add clarification that typeclasses are lingua franca

* Fix menu entry for Monads

* Fixes in code review

* Typo

* Typos

* Improve task example

* Fix wording for flatten

* Close lambdas. Improve comprehensions.

* Fix wrong API

* Fix Eugenio's concerns

* More of Eugenio's fixes

* Fix Hadi's concerns

* Fix Hadi's concerns

* Add paragraph about what monads are available
  • Loading branch information
pakoito committed Aug 1, 2018
1 parent e6c2396 commit 73b9a97
Show file tree
Hide file tree
Showing 9 changed files with 897 additions and 33 deletions.
6 changes: 5 additions & 1 deletion README.md
Expand Up @@ -7,7 +7,11 @@
[![codecov](https://codecov.io/gh/arrow-kt/arrow/branch/master/graph/badge.svg)](https://codecov.io/gh/arrow-kt/arrow)

Λrrow is a library for Typed Functional Programming in Kotlin.
It includes the most popular data types, type classes and abstractions such as `Option`, `Try`, `Either`, `IO`, `Functor`, `Applicative`, `Monad` and many more empowering users to define pure FP apps and libraries built atop higher order abstractions. Use the below list to learn more about Λrrow's main features.

Arrow aims to provide a [*lingua franca*](https://en.wikipedia.org/wiki/Lingua_franca) of interfaces and abstractions across Kotlin libraries.
For this, it includes the most popular data types, type classes and abstractions such as `Option`, `Try`, `Either`, `IO`, `Functor`, `Applicative`, `Monad` to empower users to write pure FP apps and libraries built atop higher order abstractions.

Use the list below to learn more about Λrrow's main features.

- [Documentation](http://arrow-kt.io)
- [Patterns](http://arrow-kt.io/docs/patterns/glossary/): tutorials and approaches to day-to-day challenges using FP
Expand Down
3 changes: 3 additions & 0 deletions modules/docs/arrow-docs/docs/_data/menu.yml
Expand Up @@ -28,6 +28,9 @@ options:
- title: Dependency Injection
url: /docs/patterns/dependency_injection/

- title: The Monad Tutorial
url: /docs/patterns/monads/

- title: Monad Comprehensions
url: /docs/patterns/monad_comprehensions/

Expand Down
5 changes: 4 additions & 1 deletion modules/docs/arrow-docs/docs/docs/README.md
Expand Up @@ -12,7 +12,10 @@ NOTE: The docs are currently at around 60% completion. They're the present prior
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0)

Λrrow is a library for Typed Functional Programming in Kotlin.
It includes the most popular data types, type classes and abstractions such as `Option`, `Try`, `Either`, `IO`, `Functor`, `Applicative`, `Monad` to empower users to define pure FP apps and libraries built atop higher order abstractions.

Arrow aims to provide a [*lingua franca*](https://en.wikipedia.org/wiki/Lingua_franca) of interfaces and abstractions across Kotlin libraries.
For this, it includes the most popular data types, type classes and abstractions such as `Option`, `Try`, `Either`, `IO`, `Functor`, `Applicative`, `Monad` to empower users to write pure FP apps and libraries built atop higher order abstractions.

Use the list below to learn more about Λrrow's main features.

- [Patterns](http://arrow-kt.io/docs/patterns/glossary/): tutorials and approaches to day-to-day challenges using FP
Expand Down
24 changes: 17 additions & 7 deletions modules/docs/arrow-docs/docs/docs/patterns/glossary/README.md
Expand Up @@ -28,24 +28,34 @@ You can read more about all the [datatypes]({{ '/docs/datatypes/intro' | relativ

### Typeclasses

Typeclasses define a set of functions associated to one type.
This behavior is checked by a test suite called the "laws" for that typeclass.
Typeclasses are interface abstractions that define a set of extension functions associated to one type.
These extension functions are canonical and consistent across languages and libraries;
and they have inherent mathematical properties that are testable, such as commutativity or associativity.

You can use typeclasses as a DSL to add new free functionality to an existing type
or treat them as an abstraction placeholder for any one type that can implement the typeclass.

Examples of these behaviors are: comparability ([`Eq`]({{ '/docs/typeclasses/eq' | relative_url }})),
Examples of behaviours abstracted by typeclasses are: comparability ([`Eq`]({{ '/docs/typeclasses/eq' | relative_url }})),
composability ([`Monoid`]({{ '/docs/typeclasses/monoid' | relative_url }})),
its contents can be mapped from one type to another ([`Functor`]({{ '/docs/typeclasses/functor' | relative_url }})),
or error recovery ([`MonadError`]({{ '/docs/typeclasses/monaderror' | relative_url }})).

Typeclasses have two main uses:

* Add new functionality to types. For example, if I know how to compare two objects I can add a new extension function to check for inequality.
Or if I know how to aggregate objects together, I can add an extension function for `List` that aggregates all of its elements.
The number of extra extra extension functions that you get per typeclass can be from one in `Eq` to 17 (!) in `Foldable`.

* Abstracting over behavior. Like any other interface, you can use them in your functions and classes as a way of talking about the capabilities of the implementation,
without exposing the details. This way you can create APIs that work the same for `Option`, `Try`, or `Observable`.

You can read more about all the [typeclasses]({{ '/docs/typeclasses/intro' | relative_url }}) that Arrow provides in its [section of the docs]({{ '/docs/typeclasses/intro' | relative_url }}).

One example, the typeclass `Eq` parametrized to `F` defines equality between two objects of type `F`:
Let's dive in one example. The typeclass `Eq` parametrized to `F` defines equality between two objects of type `F`:

```kotlin
interface Eq<F> {
fun F.eqv(b: F): Boolean

fun F.neqv(b: F): Boolean =
!eqv(b)
}
```

Expand Down
Expand Up @@ -9,8 +9,12 @@ permalink: /docs/patterns/monad_comprehensions/
{:.intermediate}
intermediate

Monad comprehension is the name for a programming idiom available in multiple languages.
Monad comprehensions is the name for a programming idiom available in multiple languages like JavaScript, F#, Scala, or Haskell.
The purpose of monad comprehensions is to compose sequential chains of actions in a style that feels natural for programmers of all backgrounds.
They're similar to coroutines or async/await, but extensible to existing and new types!

Let's walk through the evolution of how code was written, up to where comprehensions are today.
It'll take a couple of sections to get there, so if you're familiar with `flatMap` feel free to skip to [Comprehensions over coroutines]({{ '/docs/patterns/monad_comprehensions/#comprehensions-over-coroutines' | relative_url }}).

### Synchronous sequences of actions

Expand All @@ -37,12 +41,15 @@ They allow us to write sequenced code that can be run asynchronously over multip

### Asynchronous sequences of actions

The general representation of sequenced execution in code is called a [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}). This typeclass is a short API for sequencing code, summarised in a single function `flatMap`.
It takes as a parameter one function to be called after the current operation completes, and that function has to return another [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}) to continue the operation with.
A common renaming of `flatMap` is `andThen`. Go to the documentation page to see a deep dive on the Monad API.

The abstraction of sequencing execution of code is summarised in a single function that in Arrow is called `flatMap`,
although you may find it in other languages referred as `andThen`, `then`, `bind`, or `SelectMany`.
It takes as a parameter one function to be called after the current operation completes, and that function has to return another value to continue the operation with.
With knowledge of `flatMap` we can write sequential expressions that are ran asynchronously, even over multiple threads.
Implementations of `Monad` are available for internal types like `Try` and also integrations like [RxJava 2]({{ '/docs/integrations/rx2' | relative_url }}) and [kotlinx.coroutines]({{ '/docs/integrations/kotlinxcoroutines' | relative_url }}).

The [typeclass]({{ '/docs/typeclasses/intro' | relative_url }}) interface that abstracts sequenced execution of code via `flatMap` is called a [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}),
for which we also have a [tutorial]({{ '/docs/patterns/monads' | relative_url }}).

Implementations of [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}) are available for internal types like `Try` and also integrations like [RxJava 2]({{ '/docs/integrations/rx2' | relative_url }}) and [kotlinx.coroutines]({{ '/docs/integrations/kotlinxcoroutines' | relative_url }}).
Let's see one example using a [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}) called [`IO`]({{ '/docs/effects/io' | relative_url }}), where we fetch from a database the information about the dean of university some student attends:

```kotlin
Expand All @@ -67,6 +74,9 @@ This feature is known with multiple names: async/await, coroutines, do notation,
In Kotlin, coroutines (introduced in version 1.1 of the language) make the compiler capable of rewriting seemingly synchronous code intro asynchronous sequences.
Arrow uses this capability of the compiler to bring you coroutines-like notation to all instances of the [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}) typeclass.

This means that comprehensions are available for `Option`, `Try`, `List`, `Reader`, `Observable`, `Flux` or `IO` all the same.
In the following examples we'll use `IO` as it's a simple concurrency primitive with straightforward behavior.

Every instance of [`Monad`]({{ '/docs/typeclasses/monad' | relative_url }}) contains a method `binding` that receives a suspended function as a parameter.
This functions must return the last element of the sequence of operations.
Let's see a minimal example.
Expand Down

0 comments on commit 73b9a97

Please sign in to comment.