README.md
# Free [![Build Status][build-image]][build] [![npm Version][version-image]][version] [![Code Coverage][coverage-image]][coverage] [![Code Climate][climate-image]][climate] [![License][license-image]][license]
> Combination of a Free applicative functor and Free monad.
## API
### Types
```hs
data Par f a where
Pure :: a -> Par f a
Lift :: f a -> Par f a
Ap :: Par f (a -> b) -> Par f a -> Par f b
data Seq f a where
Pure :: a -> Seq f a
Lift :: f a -> Seq f a
Roll :: Seq f a -> (a -> Seq f b) -> Seq f b
data Concurrent f a where
Lift :: f a -> Concurrent f a
Seq :: Seq (Concurrent f) a -> Concurrent f a
Par :: Par (Concurrent f) a -> Concurrent f a
data Interpreter f g m = Interpreter
{ runSeq :: Ɐ x. f x -> m x
, runPar :: Ɐ x. f x -> g x
, seqToPar :: Ɐ x. m x -> g x
, parToSeq :: Ɐ x. g x -> m x
, Par :: TypeRep g
, Seq :: TypeRep m
}
```
### Asymptotic complexity
On all structures, complexity of:
- `chain`, `ap` and `map` is **constant**
- `fold`, `hoist`, `retract` and `graft` is **linear**
### Concurrent
Implements [Functor][], [Applicative][], [ChainRec][] and [Monad][] specifications.
It holds `Par`allel or `Seq`uential computations which are itself holding Concurrent computations. When operating on Concurrent structures it's behaving as Sequential. but in cases you want Parallel behaviour you can call `.par()` on it and it will return `Par` object which is only Applicative. then you can move back to `Concurrent` using `Concurrent.fromPar`.
#### Functor, Applicative, ChainRec and Monad functions:
- Concurrent.prototype.`map :: Concurrent f a ~> (a -> b) -> Concurrent f b`
- Concurrent.prototype.`ap :: Concurrent f a ~> Concurrent f (a -> b) -> Concurrent f b`
- Concurrent.prototype.`chain :: Concurrent f a ~> (a -> Concurrent f b) -> Concurrent f b`
- Concurrent.`chainRec :: ((a -> c, b -> c, a) -> Concurrent f c, a) -> Concurrent f b`
- Concurrent.`of :: a -> Concurrent f a`
#### other functions:
- Concurrent.`lift :: f a -> Concurrent f a`
- Concurrent.`fromSeq :: Seq (Concurrent f) a -> Concurrent f a`
- Concurrent.`fromPar :: Par (Concurrent f) a -> Concurrent f a`
- Concurrent.prototype.`seq :: Concurrent f a ~> Seq (Concurrent f) a`
- Concurrent.prototype.`par :: Concurrent f a ~> Par (Concurrent f) a`
- Concurrent.prototype.`interpret :: (Monad m, ChainRec m, Applicative g) => Concurrent f a ~> Interpreter f g m -> m a`
- Concurrent.prototype.`fold :: (Monad m, ChainRec m) => Concurrent f a ~> (Ɐ x. f x -> m x, TypeRep m) -> m a`
- Concurrent.prototype.`hoist :: Concurrent f a ~> (Ɐ x. f x -> g x) -> Concurrent g a`
- Concurrent.prototype.`retract :: (Monad m, ChainRec m) => Concurrent m a ~> TypeRep m -> m a`
- Concurrent.prototype.`graft :: Concurrent f a ~> (Ɐ x. f x -> Concurrent g x) -> Concurrent g a`
### Seq
Implements [Functor][], [Applicative][], [ChainRec][] and [Monad][] specifications.
#### Functor, Applicative, ChainRec and Monad functions:
- Seq.prototype.`map :: Seq f a ~> (a -> b) -> Seq f b`
- Seq.prototype.`ap :: Seq f a ~> Seq f (a -> b) -> Seq f b`
- Seq.prototype.`chain :: Seq f a ~> (a -> Seq f b) -> Seq f b`
- Seq.`chainRec :: ((a -> c, b -> c, a) -> Seq f c, a) -> Seq f b`
- Seq.`of :: a -> Seq f a`
#### other functions:
- Seq.`lift :: f a -> Seq f a`
- Seq.prototype.`foldSeq :: (Monad m, ChainRec m) => Seq f a ~> (Ɐ x. f x -> m x, TypeRep m) -> m a`
- Seq.prototype.`hoistSeq :: Seq f a ~> (Ɐ x. f x -> g x) -> Seq g a`
- Seq.prototype.`retractSeq :: (Monad m, ChainRec m) => Seq m a ~> TypeRep m -> m a`
- Seq.prototype.`graftSeq :: Seq f a ~> (Ɐ x. f x -> Seq g x) -> Seq g a`
### Par
Implements [Functor][] and [Applicative][] specifications.
#### Functor, Applicative, ChainRec and Monad functions:
- Par.prototype.`map :: Par f a ~> (a -> b) -> Par f b`
- Par.prototype.`ap :: Par f a ~> Par f (a -> b) -> Par f b`
- Par.`of :: a -> Par f a`
#### other functions:
- Par.`lift :: f a -> Par f a`
- Par.prototype.`foldPar :: (Applicative g) => Par f a ~> (Ɐ x. f x -> g x, TypeRep g) -> g a`
- Par.prototype.`hoistPar :: Par f a ~> (Ɐ x. f x -> g x) -> Par g a`
- Par.prototype.`retractPar :: (Applicative f) => Par f a ~> TypeRep f -> f a`
- Par.prototype.`graftPar :: Par f a ~> (Ɐ x. f x -> Par g x) -> Par g a`
### graft, hoist, retract and fold relations:
> same for graftPar, graftSeq ... variations
- `a.graft(f) ≡ a.fold(f, a.constructor)`
- `a.hoist(f) ≡ a.fold(compose(a.constructor.lift, f), a.constructor)`
- `a.retract(M) ≡ a.fold(id, M)`
- `a.fold(f, M) ≡ compose(a.retract(M), a.hoist(f))`
---
This initial version of this module was based on a bit older version of [srijs/haskell-free-concurrent][haskell-free-concurrent-old], but it was not lawful, and from v2 it's based on more resent lawful [version][haskell-free-concurrent-resent].
[Functor]: https://github.com/fantasyland/fantasy-land#functor
[Applicative]: https://github.com/fantasyland/fantasy-land#applicative
[ChainRec]: https://github.com/fantasyland/fantasy-land#chainrec
[Monad]: https://github.com/fantasyland/fantasy-land#monad
[build-image]: https://img.shields.io/travis/safareli/free/master.svg
[build]: https://travis-ci.org/safareli/free
[version-image]: https://img.shields.io/npm/v/@safareli/free.svg
[version]: https://www.npmjs.com/package/@safareli/free
[coverage-image]: https://img.shields.io/codecov/c/github/safareli/free/master.svg
[coverage]: https://codecov.io/gh/safareli/free/branch/master
[climate-image]: https://img.shields.io/codeclimate/github/safareli/free.svg
[climate]: https://codeclimate.com/github/safareli/free
[license-image]: https://img.shields.io/github/license/safareli/free.svg
[license]: https://github.com/safareli/free/blob/master/LICENSE
[haskell-free-concurrent-old]: https://github.com/srijs/haskell-free-concurrent/blob/1a56280e8d63e037cf8f9e57aa17ac6a8ac817a5/src/Control/Concurrent/Free.hs
[haskell-free-concurrent-resent]: https://github.com/srijs/haskell-free-concurrent/blob/1a56280e8d63e037cf8f9e57aa17ac6a8ac817a5/src/Control/Concurrent/Free.hs