Higher order functions, compositions and common operations for asynchronous programming in LiveScript using Promises or callbacks.
npm install async-lsThis library provides powerful higher-order functions and other utilities
for working with asynchronous functions with callbacks or ES6 promises.
Callback utility functions are in
{callbacks} = require \async-ls
and promise based functions are in
{promises} = require \async-ls
There's also a monad library accessible by:
{monads} = require \async-ls
Callback and promise functions are similar in their input arguments and their result. Callback functions return a callback function with the signature of (error, result) -> void and promise functions return a Promise object.
To get the individual functions use LiveScript pattern matching syntax:
{
promises: {
LazyPromise, parallel-map, parallel-limited-filter
},
monads: {
filterM, liftM
}
} = require \async-ls
To build:
make build
Build for browsers (using Browserify):
make async-browser.js
Build for browsers (callbacks library only):
make callbacks-browser.js
Build for browsers (promises library only):
make promises-browser.js
To test:
./test.sh
{monads} = require \async-ls
monadize encapsulates the monad's type: return aka pure, fmap and bind functions. monadize ::
(a -> m a) -> # pure
((a -> b) -> m a -> m b) -> # fmap
(m a -> (a -> m b) -> m b) -> # bind
Monad
kcompM :: (Monad m) => (a -> m b) -> (b -> m c) -> (a -> m c)
foldM function is analogous to foldl, except that its result issequenceM . (map f).monad.pureM f ap x1 ap ... ap is equivalent to (liftMn monad) f x1 x2 ... xn
ap :: (Monad m) => m (a -> b) -> m a -> m b$3
list-monad :: Monad # []
either-monad :: Monad # [error, right]
writer-monad :: Monad # [value, monoid]
Promises
{promises} = require \async-ls
Lazy Promise
LazyPromise only starts getting evaluated after then is called. LazyPromise : Promise
Compositions
promise-monad :: Monad
$3
Inject a value into a promise. returnP :: x -> Promise x
$3
Map a normal function over a promise. fmapP :: (x -> y) -> Promise x -> Promise y
$3
fmapP with its arguments flipped. ffmapP :: Promise x -> (x -> y) -> Promise y
$3
Sequentially compose two promises, passing the value produced
by the first as an argument to the second. bindP :: Promise x -> (x -> Promise y) -> Promise y
$3
bindP with its arguments flipped. fbindP :: (x -> Promise y) -> Promise x -> Promise y
$3
Filter the list by applying the promise predicate function to
each of its element one-by-one in serial order. filterP :: (x -> Promise Boolean) -> [x] -> Promise [x]
$3
The foldP function is analogous to foldl, except that its result is
encapsulated in a promise. foldP :: (a -> b -> Promise a) -> a -> [b] -> Promise a
$3
Run its input (an array of Promise s) in parallel
(without waiting for the previous promise to fulfill),
and return the results encapsulated in a promise.The returned promise immidiately gets rejected,
if any of the promises in the input list fail.
sequenceP :: [Promise x] -> Promise [x]
Lists
$3
parallel-map :: (a -> Promise b) -> [a] -> Promise [b]
$3
serial-map :: (a -> Promise b) -> [a] -> Promise [b]
$3
parallel-limited-map :: Int -> (x -> Promise y) -> [x] -> Promise [y]
$3
parallel-filter :: (x -> m Boolean) -> [x] -> m [x]
$3
Synonym for filterP serial-filter :: (x -> Promise Boolean) -> [x] -> Promise [x]
$3
parallel-limited-filter :: Int -> (x -> Promise Boolean) -> [x] -> Promise x
$3
Run the boolean predicate (that is encapsulated in a promise) on the list in parallel.
The returned promise fulfills as soon as a matching item is found with true,
otherwise false if no match was found. parallel-any :: (x -> Promise Boolean) -> [x] -> Promise Boolean
$3
serial-any :: (x -> m Boolean) -> [x] -> m Boolean
$3
parallel-limited-any :: Int -> (x -> Promise Boolean) -> [x] -> Promise Boolean
$3
parallel-all :: (x -> Promise Boolean) -> [x] -> Promise Boolean
$3
serial-all :: (x -> Promise Boolean) -> [x] -> Promise Boolean
$3
parallel-limited-all :: Int -> (x -> Promise Boolean) -> [x] -> Promise Boolean
$3
Run the boolean predicate (that is encapsulated in a promise) on the list in parallel.
The returned promisefulfills as soon as a matching item is found with the
matching value, otherwise with null if no match was found. parallel-find :: (x -> Promise Boolean) -> [x] -> m
$3
serial-find :: (x -> Promise Boolean) -> [x] -> m x
$3
parallel-limited-find :: Int -> (x -> Promise Boolean) -> [x] -> Promise x
$3
Synonym for sequenceP parallel-sequence :: [Promise x] -> Promise [x]
$3
The serial version of sequenceP.To run the list one by one in a serial order, its items
must be instances of
LazyPromise type.
This function runs the list in parallel, if it is a list
of normal Promise s. serial-sequence :: [LazyPromise x] -> LazyPromise [x]
$3
parallel-limited-sequence :: Int -> [LazyPromise x] -> LazyPromise [x]
$3
parallel-apply-each :: x -> [x -> Promise y] -> Promise [y]
$3
serial-apply-each :: x -> [x -> Promise y] -> Promise [y]
$3
parallel-limited-apply-each :: x -> [x -> Promise y] -> Promise [y]
$3
Sort the list using the given function for making the comparison between the items. parallel-sort-by :: (a -> Promise b) -> [a] -> Promise [a]
$3
parallel-sort-with takes a binary function which compares two items and returns either
a positive number, 0, or a negative number, and sorts the inputted list
using that function. parallel-sort-with :: (a -> a -> Promise i) -> [a] -> Promise [a]
$3
waterfall :: x -> (x -> Promise x) -> Promise x
$3
Bind a promise monad to an either monad. The result is a promise monad.
Since we can think of promise as a superset of either in the way it handles errors. transform-promise-either :: Promise x -> (x -> Either y) -> Promise y
$3
transform-promise-either with its arguments flipped. ftransform-promise-either :: (x -> Either y) -> Promise x -> Promise y
$3
Bind an either monad to a promise monad. transform-either-promise :: Either x -> (x -> Promise y) -> Promise y
$3
transform-either-promise with its arguments flipped. ftransform-either-promise :: (x -> Promise y) -> Either x -> Promise y
$3
Convert the promise object to a callback with the signature of (error, result) -> void Promise x -> CB x
$3
Make a promise object from a callback with the signature of (result) -> void, like fs.exist Cb x -> Promise x
$3
Make a promise object from a callback with the signature of (error, result) -> void, like fs.stat CB x -> Promise x
$3
Make a promise object from obj. String -> String -> obj -> Promise x
---
---
---
Callbacks
These functions are analogous to their promise-based counterparts that are documented above.
But instead of a Promise their last argument is a callback. You can think of curried version of these functions as functions that return a function that takes callback. {callbacks} = require \prelude-ls
Convention
This would be our definition of asynchronous functions:
> If function
f returns function g and g takes a callback as its only argument; then f is an asynchronous function.Our callbacks will always receive two parameters:
(error, result).Here
CB a stands for a callback function with signature: (err, a) -> void
You can get the result of an asynchronous function (with a callback of type of CB a) by: (err, a) <- f
Composition of Asynchronous Actions
$3
Inject a value into an asynchronous action. returnA :: x -> CB x
$3
Map a normal function over an asynchronous action. fmapA :: (x -> y) -> CB x -> CB y
$3
fmapA with its arguments flipped ffmapA :: CB x -> (x -> y) -> CB y
$3
Sequentially compose two asynchronous actions, passing the value produced
by the first as an argument to the second. bindA :: CB x -> (x -> CB y) -> CB y
$3
bindA with its arguments flipped fbindA :: (x -> CB y) -> CB x -> CB y
$3
Similar to Left-to-right Kleisli composition, kcompA composes
two asynchronous actions passing the value produced
by the first as an argument to the second. The result is a new
asynchronous function that takes the argument of the first function. kcompA :: (x -> CB y) -> (y -> CB z) -> (x -> CB z)
$3
The foldA function is analogous to foldl, except that its result is
encapsulated in an asynchronous callback. foldA :: (a -> b -> m a) -> a -> [b] -> m a
$3
Evaluate each action in the sequence from left to right, and collect the results. sequenceA :: [CB x] -> CB [x]
$3
Filter the list by applying the asynchronous predicate function. filterA :: (x -> CB Boolean) -> [x] -> CB [x]
Either
$3
Inject a value into an either action. returnE :: x -> Either x
$3
fmapE :: (x -> y) -> Either x -> Either y
$3
ffmapE :: Either x -> (x -> y) -> Either y
$3
bindE :: Either x -> (x -> Either y) -> Either y
$3
bindE :: (x -> Either y) -> Either x -> Either y
$3
Left to right Kleisli composition
kcompE :: (x -> Either y) -> (y -> Either z) -> (x -> Either z)
$3
foldE :: (a -> b -> Either a) -> a -> [b] -> Either a
$3
sequenceE :: [Either x] -> Either [x]
$3
transformAE :: CB x -> (x -> Either y) -> CB y
$3
ftransformAE :: (x -> Either y) -> CB x -> CB y
$3
transformEA :: Either x -> (x -> CB y) -> CB y
$3
ftransformEA :: (x -> CB y) -> Either x -> CB y
Lists
Map
$3
parallel-map :: (a -> CB b) -> [a] -> CB [b]
$3
Serial Asynchronous Map serial-map :: (a -> CB b) -> [a] -> CB [b]
$3
Similar to parallel-map, only no more than
limit` iterators will be simultaneously running at any time.parallel-map-limited :: Int -> (x -> CB y) -> [x] -> CB [y]
parallel-filter :: (x -> CB Boolean) -> [x] -> CB [x]
serial-filter :: (x -> CB Boolean) -> [x] -> CB [x]
parallel-limited-filter :: Int -> (x -> CB Boolean) -> [x] -> CB x
parallel-any :: (x -> CB Boolean) -> [x] -> CB Boolean
serial-any :: (x -> CB Boolean) -> [x] -> CB Boolean
parallel-limited-any :: Int -> (x -> CB Boolean) -> [x] -> CB Boolean
parallel-all :: (x -> CB Boolean) -> [x] -> CB Boolean
serial-all :: (x -> CB Boolean) -> [x] -> CB Boolean
parallel-limited-all :: Int -> (x -> CB Boolean) -> [x] -> CB Boolean
paralel-find :: (x -> CB Boolean) -> [x] -> CB x
serial-find :: (x -> CB Boolean) -> [x] -> CB x
parallel-sort-by :: (a -> CB b) -> [a] -> CB [a]
parallel-sort-with :: (a -> a -> CB i) -> [a] -> CB [a]
parallel-sequence :: [CB x] -> CB [x]
parallel-limited-sequence :: Int -> [CB x] -> CB [x]
parallel-apply-each :: x -> [x -> CB y] -> CB [y]
serial-apply-each :: x -> [x -> CB y] -> CB [y]
parallel-limited-apply-each :: x -> [x -> CB y] -> CB [y]
waterfall :: x -> (x -> CB x) -> CB x
serial-fold :: (a -> b -> m a) -> a -> [b] -> m a