`rmonad`

: Where’s the monad?This work is funded by the National Science Foundation grant NSF-IOS 1546858.

You probably don’t need to read this. Certainly you should read the `introduction`

vignette first.

** This vignette is under construction **

This vignette consists of four parts. First I will describe the monad hidden in the R runtime. Second, I will describe how `rmonad`

can serve as a replacement. Third, I will contrast the monadic pipelines of `rmonad`

with the compositional pipelines of `magrittr`

. Finally, I will discuss `rmonad`

from the Haskell perspective.

I will introduce the concept of a monad incrementally through the first three sections. However, monads in the programming context are notoriously difficult to understand. If you are not familiar with them, you may try studying a few online tutorials first. That said, `rmonad`

can be used without understanding monads.

`rmonad`

The goal of `rmonad`

is to ditch the existing impure R monad and replace it with a clean explicit monad.

`x %>>% sum %>>% sqrt`

The initial %>>% operators acts as both a `return`

and `bind`

function. It first evaluates the

`m b`

is dependent on `m a`

, not just on `a`

. The `bind`

function can pass information from one step in the pipeline `m a`

to the next `m b`

.

`m2 b`

is equal to `m3 b`

only for the trivial case where the context is `identity`

.

R users normally rely on the R session to automatically perform these binds.

But what exactly is `m`

? In an R session, the R runtime handles errors. If one function raises an error, the error is propagated to functions that use its input.

In `rmonad`

, the `m`

is an object, that catches all undefined behavior.

`rmonad`

versus magrittrTo understand the monadic nature of `rmonad`

it is useful to compare it to `magrittr`

. In `magrittr`

, the expression `x %>% foo %>% bar`

is the same as `bar(foo(x))`

. From a monadic point of view, `x`

is first implicitly raised into an ‘Identity’ monad (which is quite formless here) `m1 x`

. Then

`bind :: m1 x -> (x -> m2 y) -> m3 y`

The `bind`

function above executes `foo`

on `x`

, yielding `m2 y`

. It then reduces this to `m3 y`

in the presence of `m1`

. But `magrittr`

passes no information from `m1`

to `m3`

. The pipeline is context indepent.

In `rmonad`

, the pipeline `x %>>% foo %>>% bar`

will pass a record of past events at each bind operation, thus incrementally building a graph of the pipeline.

`rmonad`

for HaskellersThe name `rmonad`

is a nod to `Xmonad`

(no relation to the Restricted Monad package). Where `Xmonad`

wraps the X window system, `rmonad`

wraps evaluation of R expressions.

Only a few R expressions are pure. If a function is given an invalid input at runtime (e.g. `sqrt("wtf")`

), it will die with a message printed to stderr. `rmonad`

wraps all R calls in a monad, intercepting all messages, so that the result of a computation is returned as a pure object.

The ‘R monad’ is one monad to rule the all. There is no monad stack and no support for monad transformers. In addition to error handling, The monad stores the history of every previous operation. It also performs basic benchmarking, recording the time required for each operation and the size of the returned object. All this weight might seem like a performance killer, but R programmers are used to function calls being slow, so if they care about performance, they wouldn’t use a function in a tight loop anyways.

The `return`

function is a little complex in `rmonad`

. It is a special case of the `as_monad`

function:

`as_monad = a -> m b`

Where `a`

can be one of three types

an unevaluated R expression -

`as_monad`

evaluates the expression, capturing any exceptions, warnings or messages.`as_monad`

is used inside the`bind`

function in this capacity.a pure R value - acts as

`return`

The `%>>%`

operator is like the Haskell `>>=`

operator, but with some of the sloppiness expected of a dynamic language:

```
%>>% :: m a -> (a -> m b) -> m b
| a -> (a -> m b) -> m b
| (a -> r b) -> (a -> m b) -> m b
```

`%>>%`

differs from `>>=`

in that `%>>%`

automatically loads the left-hand-side value into a monad.