https://github.com/homam/async-ls
Higher order functions, compositions and common operations for asynchronous programming in LiveScript.
https://github.com/homam/async-ls
Last synced: 20 days ago
JSON representation
Higher order functions, compositions and common operations for asynchronous programming in LiveScript.
- Host: GitHub
- URL: https://github.com/homam/async-ls
- Owner: homam
- Created: 2014-04-04T22:14:37.000Z (almost 12 years ago)
- Default Branch: master
- Last Pushed: 2014-08-17T20:19:03.000Z (over 11 years ago)
- Last Synced: 2025-10-27T18:30:06.416Z (4 months ago)
- Language: LiveScript
- Size: 563 KB
- Stars: 9
- Watchers: 1
- Forks: 2
- Open Issues: 1
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
- awesome-functional-programming - **async-ls** - Higher order functions, compositions and common operations for asynchronous programming in LiveScript
- awesome-functional-programming - **async-ls** - Higher order functions, compositions and common operations for asynchronous programming in LiveScript
README
# async-ls
This 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
{monads} = require \async-ls
### monadize
Monads work best in statically typed languages. To make monadic functions
work in LiveScript, we need to pass the type of the monad to many of the monadic operations.
`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
Left-to-right Kleisli composition of monads.
kcompM :: (Monad m) => (a -> m b) -> (b -> m c) -> (a -> m c)
### joinM
Remove one level of monadic structure, projecting its bound argument into the outer level.
(Monad m) => m m x -> m x
### filterM
Filter the list by applying the predicate function to
each of its element one-by-one in serial order.
filterM :: (Monad x) => (x -> m Boolean) -> [x] -> m [x]
### foldM
The `foldM` function is analogous to `foldl`, except that its result is
encapsulated in a monad.
foldM :: (Monad a) => (a -> b -> m a) -> a -> [b] -> m a
### sequenceM
Evaluate each action in the sequence from left to right,
and collect the results.
sequenceM :: (Monad x) => [m x] -> m [x]
### mapM
It is equivalent to `sequenceM . (map f)`.
(Monad m) => (x -> m x) -> [x] -> m [x]
### liftM
Promote a function to a monad.
liftM :: (Monad m) => (a -> r) -> m a -> m r
### liftM2
Promote a function to a monad, scanning the monadic arguments from
left to right.
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
### ap
``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
### Some Monad Instances:
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
### returnP
Inject a value into a promise.
returnP :: x -> Promise x
### fmapP
Map a normal function over a promise.
fmapP :: (x -> y) -> Promise x -> Promise y
### ffmapP
`fmapP` with its arguments flipped.
ffmapP :: Promise x -> (x -> y) -> Promise y
### bindP
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
### fbindP
`bindP` with its arguments flipped.
fbindP :: (x -> Promise y) -> Promise x -> Promise y
### filterP
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]
### foldP
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
### sequenceP
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
### parallel-map
parallel-map :: (a -> Promise b) -> [a] -> Promise [b]
### serial-map
serial-map :: (a -> Promise b) -> [a] -> Promise [b]
### parallel-limited-map
parallel-limited-map :: Int -> (x -> Promise y) -> [x] -> Promise [y]
### parallel-filter
parallel-filter :: (x -> m Boolean) -> [x] -> m [x]
### serial-filter
Synonym for `filterP`
serial-filter :: (x -> Promise Boolean) -> [x] -> Promise [x]
### parallel-limited-filter
parallel-limited-filter :: Int -> (x -> Promise Boolean) -> [x] -> Promise x
### parallel-any
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
### serial-any
serial-any :: (x -> m Boolean) -> [x] -> m Boolean
### parallel-limited-any
parallel-limited-any :: Int -> (x -> Promise Boolean) -> [x] -> Promise Boolean
### parallel-all
parallel-all :: (x -> Promise Boolean) -> [x] -> Promise Boolean
### serial-all
serial-all :: (x -> Promise Boolean) -> [x] -> Promise Boolean
### parallel-limited-all
parallel-limited-all :: Int -> (x -> Promise Boolean) -> [x] -> Promise Boolean
### parallel-find
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
### serial-find
serial-find :: (x -> Promise Boolean) -> [x] -> m x
### parallel-limited-find
parallel-limited-find :: Int -> (x -> Promise Boolean) -> [x] -> Promise x
### parallel-sequence
Synonym for `sequenceP`
parallel-sequence :: [Promise x] -> Promise [x]
### serial-sequence
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]
### parallel-limited-sequence
parallel-limited-sequence :: Int -> [LazyPromise x] -> LazyPromise [x]
### parallel-apply-each
parallel-apply-each :: x -> [x -> Promise y] -> Promise [y]
### serial-apply-each
serial-apply-each :: x -> [x -> Promise y] -> Promise [y]
### parallel-limited-apply-each
parallel-limited-apply-each :: x -> [x -> Promise y] -> Promise [y]
### parallel-sort-by
Sort the list using the given function for making the comparison between the items.
parallel-sort-by :: (a -> Promise b) -> [a] -> Promise [a]
### parallel-sort-with
`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]
### waterfall
waterfall :: x -> (x -> Promise x) -> Promise x
### transform-promise-either
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
### ftransform-promise-either
`transform-promise-either` with its arguments flipped.
ftransform-promise-either :: (x -> Either y) -> Promise x -> Promise y
### transform-either-promise
Bind an either monad to a promise monad.
transform-either-promise :: Either x -> (x -> Promise y) -> Promise y
### ftransform-either-promise
`transform-either-promise` with its arguments flipped.
ftransform-either-promise :: (x -> Promise y) -> Either x -> Promise y
### to-callback
Convert the promise object to a callback with the signature of `(error, result) -> void`
Promise x -> CB x
### from-value-callback
Make a promise object from a callback with the signature of `(result) -> void`, like `fs.exist`
Cb x -> Promise x
### from-error-value-callback
Make a promise object from a callback with the signature of `(error, result) -> void`, like `fs.stat`
CB x -> Promise x
### from-named-callbacks
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
### returnA
Inject a value into an asynchronous action.
returnA :: x -> CB x
### fmapA
Map a normal function over an asynchronous action.
fmapA :: (x -> y) -> CB x -> CB y
### ffmapA
fmapA with its arguments flipped
ffmapA :: CB x -> (x -> y) -> CB y
### bindA
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
### fbindA
bindA with its arguments flipped
fbindA :: (x -> CB y) -> CB x -> CB y
### kcompA
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)
### foldA
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
### sequenceA
Evaluate each action in the sequence from left to right, and collect the results.
sequenceA :: [CB x] -> CB [x]
### filterA
Filter the list by applying the asynchronous predicate function.
filterA :: (x -> CB Boolean) -> [x] -> CB [x]
## Either
### returnE
Inject a value into an either action.
returnE :: x -> Either x
### fmapE
fmapE :: (x -> y) -> Either x -> Either y
### fmapE
ffmapE :: Either x -> (x -> y) -> Either y
### bindE
bindE :: Either x -> (x -> Either y) -> Either y
### bindE
bindE :: (x -> Either y) -> Either x -> Either y
### kcompE
Left to right Kleisli composition
kcompE :: (x -> Either y) -> (y -> Either z) -> (x -> Either z)
### foldE
foldE :: (a -> b -> Either a) -> a -> [b] -> Either a
### sequenceE
sequenceE :: [Either x] -> Either [x]
### transformAE
transformAE :: CB x -> (x -> Either y) -> CB y
### ftransformAE
ftransformAE :: (x -> Either y) -> CB x -> CB y
### transformEA
transformEA :: Either x -> (x -> CB y) -> CB y
### ftransformEA
ftransformEA :: (x -> CB y) -> Either x -> CB y
# Lists
## Map
### parallel-map
parallel-map :: (a -> CB b) -> [a] -> CB [b]
### serial-map
Serial Asynchronous Map
serial-map :: (a -> CB b) -> [a] -> CB [b]
### parallel-map-limited
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]
## Filter
### parallel-filter
parallel-filter :: (x -> CB Boolean) -> [x] -> CB [x]
### serial-filter
serial-filter :: (x -> CB Boolean) -> [x] -> CB [x]
### parallel-limited-filter
parallel-limited-filter :: Int -> (x -> CB Boolean) -> [x] -> CB x
## Any, All, Find
### parallel-any
parallel-any :: (x -> CB Boolean) -> [x] -> CB Boolean
### serial-any
serial-any :: (x -> CB Boolean) -> [x] -> CB Boolean
### parallel-limited-any
parallel-limited-any :: Int -> (x -> CB Boolean) -> [x] -> CB Boolean
### parallel-all
parallel-all :: (x -> CB Boolean) -> [x] -> CB Boolean
### serial-all
serial-all :: (x -> CB Boolean) -> [x] -> CB Boolean
### parallel-limited-all
parallel-limited-all :: Int -> (x -> CB Boolean) -> [x] -> CB Boolean
### parallel-find
paralel-find :: (x -> CB Boolean) -> [x] -> CB x
### serial-find
serial-find :: (x -> CB Boolean) -> [x] -> CB x
## Sort
### parallel-sort-by
Sorts a list using the inputted function for making the comparison between the items.
parallel-sort-by :: (a -> CB b) -> [a] -> CB [a]
### 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 -> CB i) -> [a] -> CB [a]
## Control Flow
### serial-sequence
serial-sequence :: [CB x] -> CB [x]
### parallel-sequence
Run its sole input (a tasks array of functions) in parallel,
without waiting until the previous function has completed.
If any of the functions pass an error to its callback,
the main callback is immediately called with the value of the error.
Once the tasks have completed, the results are passed to the final callback as an array.
parallel-sequence :: [CB x] -> CB [x]
### parallel-limited-sequence
parallel-limited-sequence :: Int -> [CB x] -> CB [x]
### parallel-apply-each
parallel-apply-each :: x -> [x -> CB y] -> CB [y]
### serial-apply-each
serial-apply-each :: x -> [x -> CB y] -> CB [y]
### parallel-limited-apply-each
parallel-limited-apply-each :: x -> [x -> CB y] -> CB [y]
### waterfall
waterfall :: x -> (x -> CB x) -> CB x
### serial-fold
serial-fold :: (a -> b -> m a) -> a -> [b] -> m a