/**
* Created by elydelacruz on 2/19/2017.
* Io module - Contains `IO` class.
* Fore more on io class
* @see http://learnyouahaskell.com/input-and-output
* @module io
*/
import Monad, {unWrapMonadByType} from '../monad/Monad';
import {compose, toFunction} from 'fjl';
/**
* @class io.IO
* @param fn {Function} - Operation to contain within `IO`
* @property `value` {*} - `IO` however wraps non-function values to `function` on construction.
* @extends module:monad.Monad
*/
export default class IO extends Monad {
/**
* Unwraps an `IO`.
* @function module:io.IO.unWrapIO
* @static
* @param io {IO}
* @returns {*}
*/
static unWrapIO (io) {
if (!IO.isIO(io)) { return io; }
return unWrapMonadByType(IO, io);
}
/**
* Applicative pure; Same as `new IO(...)`.
* @function module:io.IO.of
* @static
* @param fn {Function} - Unary operation.
* @returns {IO}
*/
static of(fn) {
return new IO(fn);
}
/**
* Checks for `IO`.
* @function module:io.IO.isIO
* @static
* @param x {*}.
* @returns {boolean}
*/
static isIO (x) {
return x instanceof IO;
}
/**
* Performs io.
* @function module:io.IO.isIO
* @static
* @param io {IO}.
* @param args {...*} {IO}.
* @returns {boolean}
*/
static do (io, ...args) {
const instance = !IO.isIO(io) ? new IO(io) : io;
return compose(
IO.of,
IO.unWrapIO
)(
toFunction(instance.join())(...args)
);
}
constructor(fn) {
super(toFunction(fn));
}
/**
* Maps incoming function onto contained, innermost, value
* and returns a new `IO` which will containe the result of calling incoming function on originally contained value - A.k.a - flat-map operation.
* @memberOf module:io.IO
* @param fn {Function} - Unary operation.
* @returns {IO}
*/
flatMap (fn) {
return compose(
this.constructor.of,
IO.unWrapIO, fn,
IO.unWrapIO
)(
toFunction(this.join())()
);
}
/**
* Maps incoming function on contained value and returns
* a new `IO` container containing result of unary operation (incoming-function's result).
* @memberOf module:io.IO
* @param fn {Function}
* @returns {IO}
*/
map (fn) {
return compose(
this.constructor.of,
fn
)(
toFunction(this.valueOf())()
);
}
}