# Relude.IO

## Overview

`Relude.IO` contains a type `t('a, 'e)` and related functions for representing and controlling the execution of side effects.  A side effect is any application state change or behavior which can be observed outside a function other than its returned value.  Side effects are basically where the "work gets done" in a program or application, but controlling when the side effects are executed makes your code more [pure](https://en.wikipedia.org/wiki/Pure_function), easier to reason about, easier to reuse, and easier to safely and confidently refactor.  This type is inspired by and based on the recent work that has gone into the concept of bi-functor IO in the FP community:

* John De Goes' blogs
    * [Bifunctor IO: A Step Away from Dynamically-Typed Error Handling](http://degoes.net/articles/bifunctor-io)
    * [Beautiful, Simple, Testable Functional Effects for Scala](http://degoes.net/articles/zio-environment)
* [ZIO](https://github.com/scalaz/scalaz-zio)
* [cats-bio](https://github.com/LukaJCB/cats-bio)
* [PureScript Aff Discussion](https://github.com/slamdata/purescript-aff/issues/137)

`IO` can represent any type of synchronous or asynchronous side effect that can either produce a value (in the success channel `'a`) or an error (in the error channel `'e`).  The main purpose of `IO` is to make side-effectful code [referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency) and to allow you to control when side effects are executed or "run."  When you construct an `IO`, in most cases you are just suspending the execution of a side effect, rather than allowing it to execute immediately.  In the case of a synchronous effect like a `console.log(...)`, which writes to the console, or `Date.now()`, which reads the current clock time from the system, or `Math.random()`, which generates a random number out of the blue, it simply makes the action lazy, using a thunk like `unit => effect`.  In the case of asynchronous side effects, it suspends the start of execution of the asynchronous action until the `IO` is run.  There is no magic with `IO` - it simply "holds onto" effects in a suspended state (e.g. a thunk `unit => 'a`)) until you run the `IO` using `unsafeRunAsync`.  Because `IO` can represent both synchronous and asynchronous side effects, the end result of executing an `IO` (`unsafeRunAsync`) is asynchronous (i.e. the value or error is given to the caller via an async callback).

### Why is running an `IO` considered unsafe?

An `IO` value represents a "description" or "recipe" of one or more side effects to perform.  When you run an `IO`, all of the suspended effects are executed, and all of the side effects will occur.  Naming the run function `unsafeRunAsync` is intended to warn you that invoking the function will execute your side effects.  Describing these functions as "unsafe" is a convention in the FP community for performing `IO` effects - see [Haskell IO](http://hackage.haskell.org/package/base-4.12.0.0/docs/System-IO-Unsafe.html), [Purescript Effect](https://pursuit.purescript.org/packages/purescript-effect/2.0.1/docs/Effect.Unsafe#v:unsafePerformEffect), [Cats Effect IO](https://typelevel.org/cats-effect/datatypes/io.html#unsafe-operations).

### Relation to `Js.Promise`

If you are coming from the JavaScript world, don't be afraid of `IO` - in many ways, you can basically just think of it as a construct similar to `Promise`, with the following key differences:

1. `Promise` is eagerly-executed and `IO` is lazily-executed.  When you construct a `Promise` its execution is immediately started, and it will invoke it's success or failure callbacks whenever it finishes.  `IO` is lazily-executed, so it will not do anything until you "run" the `IO` using `unsafeRunAsync`, which provides you with the resulting value or error using a callback from `Belt.Result.t('a, 'e) => unit`.  Just think of `IO` as something like a `Promise`, but instead of starting it by constructing it, you explicitly start it later on by calling `unsafeRunAsync`.
1. `Promise` [memoizes](https://en.wikipedia.org/wiki/Memoization) its result value, and `IO` does not.  This means that once a `Promise` is resolved or rejected, it will hold onto the resulting value or error, and any future uses of `then` or `catch` will produce that same value or error, rather than re-running the `Promise` and producing a new value or error.  `IO` doesn't have built-in memoization of the value, so re-running an `IO` will cause all the effects to be re-run, and a new value (or error) will be produced.
1. A `Promise` can fail (be rejected) with any type of value, and in JavaScript, the only way to tell what type of error occurred is to inspect the error value and/or its type at runtime.  When translated to the ReasonML world, this means that the error type produced by `Js.Promise` can't be known at compile time, so is simply represented by a completely [opaque type](https://bucklescript.github.io/bucklescript/api/Js.Promise.html#TYPEerror).  This makes error handling a runtime coercion problem, rather than a compile time problem.  Because `Promise` can fail with any type of error, you can think of a `Promise` as having an implicit error type like an `any` type - it can fail with any type of error.  If you've ever worked with a language that has an `any` type, you've probably experienced some pain in dealing with those types of values.  On the other hand, `IO.t('a, 'e)` represents the error as an explicit type, which you can control and manipulate at compile time.  This gives you the freedom to represent an error in the most appropriate way for each scenario.  In some scenarios you may not care what the error is, you just care whether the operation failed, so you could use the equivalent of the `Js.Promise` opaque error type, or even `unit` as the error type.  In cases where you do care what types of errors can occur, and want to handle them, you can use your own variant type, a custom error type, or whatever makes the most sense for your use case.  There is no silver bullet in figuring out what type to use for the error, but having the flexibility to choose makes error handling much easier than dealing with runtime coercions and trying to guess what types of errors might occur, and how to catch them.

### More about "effects"

The word "effect" is a bit overloaded in the functional programming world.  We often hear about "side effects," and this term is typically referring to things like writing to stdout, making a network call, getting the system time, generating a random number using something like JavaScript's `Math.random` - these are all things that either send information to the outside world, or pull information in from the outside world.  They are called "side effects" because the function has an effect on the system beyond its input arguments and output return value - it does something that is not represented by the input and output types.

Another place in functional programming where the term "effect" appears is when we talk about data types like `option('a)` or `Belt.Result.t('a, 'e)` - these types of values are often called "effectful" values, because they represent some sort of additional "effect" that may have occurred (note: we're not talking about "side effects" in the above sense).  For example if you have a function `a => b`, assuming it's a pure function that doesn't throw exceptions, the only possible value you can get out of the function is a value of type `'b` - there's no way to represent a failure, an asynchronous computation, or a case where the function can't produce a value.  If instead the function is `'a => option('b)`, the function can now either produce a value of type `'a`, or fail to produce a value (`None`).  This behavior is often called the "effect" of producing a value with the possibility of not being able to produce a value.  For `'a => Belt.Result.t('b, 'e)`, we have the "effect" of either producing a value or an error.  `Js.Promise` is another effectful value in that it has the "effect" of asynchronous computation (a value will be produced at some time later), and the "effect" of possible failure.  In terms of `IO`, this is important because not only can `IO` suspend actual "side effects" (like stdout/network/etc.), but it can also represent the types of "effects" like `option('a)`, `Belt.Result.t('a, 'e)`, `Js.Promise.t`, etc.  All of these types of "effectful" values can be converted to an `IO`, so that you can easily compose all of these different effects in a single expression.  When you try to write code in the monadic style (e.g. using chained `bind`/`flatMap`/`>>=` operations), it can be quite convenient to be able to deal with various types of side effects and "functional effects" using a single Monad.

## Usage

TODO