UNPKG

lazy-either

Version:

A lazy implementation of the Fantasy Land Either type

182 lines (113 loc) 6.55 kB
# LazyEither [![Build Status](https://travis-ci.org/Risto-Stevcev/lazy-either.svg)](https://travis-ci.org/Risto-Stevcev/lazy-either) The `LazyEither` type is used to represent a lazy `Either` value. It is similar to the `Future` and `Promise` types. The constructor continuation function parameter and *eventual* return value is an `Either` type. The execution is delayed until the value is requested using one of it's methods. The implementation is more favorable than the `Future` type because it is very easy to compose elegant pipelines, and it handles errors nicely. If `fork`-like branching is desired, it can be done just by resolving the pipeline using `value` and checking whether the result `isLeft` or `isRight` (though branching is not usually needed). See the examples section for more details. The implementation follows the [Fantasy Land](https://github.com/fantasyland/fantasy-land) specifications. The `LazyEither` type is a `Functor`, `Applicative` and `Monad`. It is not (necessarily) a `Setoid` due to its lazy/deferred nature. ## Construction The `LazyEither` type consists of a single constructor that accepts a function which must accept a continuation function used to resolve the `LazyEither` instance into an `Either` type: ```hs LazyEither :: ((Either e a -> ()) -> ()) -> LazyEither e a ``` The resolved instance should be an [Either type](https://github.com/ramda/ramda-fantasy/blob/master/docs/Either.md). ```js //:: (Number, a) -> LazyEither (Either e a) let delayed = (ms, val) => LazyEither(resolve => { ms > 1000 ? resolve(S.Left(Error('Delay too long'))) : setTimeout(() => resolve(S.Right(val)), ms) }) ``` ```js delayed(500, 'Hello').value(console.log) // returns Right('Hello') delayed(1001, 'Hey').value(console.log) // returns Left(Error('Delay too long')) ``` ## Interaction Once a `LazyEither` instance has been created, the various methods attached to the instance can be used to instruct further transformations to take place. Nothing is actually executed until the `value` or `fantasy-land/equals` method is called. The `fantasy-land/map`, `fantasy-land/ap` and `fantasy-land/chain` functions can be used to transform resolved values of a `LazyEither` instance. ```js //:: String -> String -> String const join = S.curry2(path.join) //:: String -> LazyEither (Either e [String]) const ls = path => LazyEither(resolve => fs.readdir(path, (err, files) => resolve(err ? S.Left(err) : S.Right(S.map(join(path), files))))) //:: String -> LazyEither (Either e String) const cat = file => LazyEither(resolve => fs.readFile(file, {encoding: 'utf8'}, (err, data) => resolve(err ? S.Left(err) : S.Right(data)))) //:: String -> LazyEither (Either e String) const catDir = S.pipe([ls, S.chain(S.traverse(LazyEither, cat)), S.map(S.unlines)]) ``` A `LazyEither` instance is executed when `value` or `fantasy-land/equals` gets called: ```js catDir(os.homedir()).value(S.either(console.error, console.log)) ``` ## Reference ### Constructors #### `LazyEither` ```hs :: ((Either e a -> ()) -> ()) -> LazyEither e a ``` Constructs a `LazyEither` instance that represents some action that may possibly fail. It takes a function which must accept a continuation function that takes an `Either` type used to represent success or failure. #### `LazyEither.Right` ```hs :: a -> LazyEither e a ``` Creates a `LazyEither` instance that resolves to a `Right` with the given value. #### `LazyEither.Left` ```hs :: e -> LazyEither e a ``` Creates a `LazyEither` instance that resolves to a `Left` with the given value. ### Static methods #### `LazyEither['fantasy-land/of']` ```hs :: a -> LazyEither e a ``` Creates a pure instance that resolves to a `Right` with the given value. #### `LazyEither.lift` ```hs :: (a -> b) -> a -> LazyEither e b ``` Lifts a function of arity `1` into one that returns a `LazyEither` instance. #### `LazyEither.liftN` ```hs :: n -> (a -> .. -> z) -> a -> .. -> z -> LazyEither e z ``` Lifts a function of arity `n` into one that returns a `LazyEither` instance. #### `LazyEither.promote` ```hs :: Either a b -> LazyEither a b ``` Promotes an `Either` type to a `LazyEither` type. ### Instance methods #### `lazyEither['fantasy-land/map']` ```hs :: LazyEither e a ~> (a -> b) -> LazyEither e b ``` Transforms the resolved `Either` value of this `LazyEither` instance with the given function. If the instance resolves as a `Left` value, the provided function is not called and the returned `LazyEither` instance will resolve with that `Left` value. #### `lazyEither['fantasy-land/ap']` ```hs :: LazyEither e a ~> LazyEither e (a -> b) -> LazyEither e b ``` Applies the `Either` function of the provided `LazyEither` instance to the `Either` value of this `LazyEither` instance, producing a `LazyEither` instance of the result. If either `LazyEither` resolves as a `Left` value, then the returned `LazyEither` instance will resolve with that `Left` value. #### `lazyEither['fantasy-land/chain']` ```hs :: LazyEither e a ~> (a -> LazyEither e b) -> LazyEither e b ``` Calls the provided function with the value of this `LazyEither` instance, returning the new `LazyEither` instance. If either `LazyEither` instance resolves as a `Left` value, the returned `LazyEither` instance will resolve with that `Left` value. The provided function can be used to try to recover the error. #### `lazyEither['fantasy-land/bimap']` ```hs :: LazyEither e a ~> (e -> f) -> (a -> b) -> LazyEither f b ``` Uses the provided functions to transform this `LazyEither` instance when it resolves to a `Left` or a `Right` value, respectively. #### `lazyEither.value` ```hs :: LazyEither e a ~> (Either e a -> ()) -> () ``` Calls the provided function with the value of this `LazyEither` instance without returning a new `LazyEither` instance. It is similar to `Future.fork`. This function can be used as a final processing step for the returned `Either` value, or to create a branch of two seperate execution streams to handle the resolved `Left` or `Right` value. #### `lazyEither['fantasy-land/equals']` ```hs :: LazyEither a b ~> LazyEither c d -> (Boolean -> ()) -> () ``` Compares the `Either` value of this `LazyEither` instance with the `Either` value of the provided `LazyEither` instance, and calls the provided function with the `Boolean` result of the comparison. Like `value`, this function will resolve the pipeline. The result will return `true` if both `Either` values match or `false` if they do not match.