New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

pacta

Package Overview
Dependencies
Maintainers
1
Versions
11
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

pacta - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

example/codenames-2.js

27

example/codenames.js

@@ -0,3 +1,20 @@

/* A simple demonstration of using Pacta to compose asynchronous HTTP requests.
*
* When run, this program will output four random code names as generated by
* Clive Murray's http://codenames.clivemurray.com.
*
* In this example, http.getJSON() returns a Promise of the parsed JSON from the
* given URL. For these specific URLs, an array of objects will be returned (one
* URL returns a list of "prefixes" and the other returns a list of animal
* names).
*
* Due to the fact two arrays are returned, concatenating the two promises
* together would join them into one but we actually want to keep them separate
* so that we can choose a random entry from each. To do this, we use append to
* append each promise's value to an empty array.
*
* See examples/codenames-2.js for another way to achieve the same result.
*/
var http = require('./promised-http'),
getJSON = http.getJSON;
Promise = require('../lib/pacta').Promise;

@@ -8,8 +25,8 @@ var random = function (coll) {

var promisedPrefixes = getJSON('http://codenames.clivemurray.com/data/prefixes.json'),
promisedAnimals = getJSON('http://codenames.clivemurray.com/data/animals.json'),
prefixesAndAnimals = promisedPrefixes.combine(promisedAnimals);
var promisedPrefixes = http.getJSON('http://codenames.clivemurray.com/data/prefixes.json'),
promisedAnimals = http.getJSON('http://codenames.clivemurray.com/data/animals.json'),
prefixesAndAnimals = Promise.of([]).append(promisedPrefixes).append(promisedAnimals);
var promisedCodeName = function () {
return prefixesAndAnimals.explode(function (prefixes, animals) {
return prefixesAndAnimals.spread(function (prefixes, animals) {
var prefix = random(prefixes),

@@ -16,0 +33,0 @@ animal = random(animals);

22

lib/pacta.js

@@ -88,20 +88,16 @@ var events = require('events');

Promise.prototype.conjoin = function (other) {
var list = function (x) { return [].concat(x); };
var wrap = function (x) { return [].concat(x); };
return this.map(list).concat(other.map(list));
return this.map(wrap).concat(other.map(wrap));
};
/* combine :: Promise [a] -> Promise [b] -> Promise [[a] [b]]
* combine :: Promise [a] -> Promise b -> Promise [[a] b]
* combine :: Promise a -> Promise [b] -> Promise [a [b]]
* combine :: Promise a -> Promise b -> Promise [a b]
*/
Promise.prototype.combine = function (other) {
var wrap = function (x) { return [x]; };
return this.map(wrap).concat(other.map(wrap));
/* append :: Promise [a] -> Promise b -> Promise [a b] */
Promise.prototype.append = function (other) {
return this.concat(other.map(function (x) {
return [x];
}));
};
/* explode :: Promise a -> (a -> b) -> Promise b */
Promise.prototype.explode = function (f) {
/* spread :: Promise a -> (a -> b) -> Promise b */
Promise.prototype.spread = Promise.prototype.explode = function (f) {
return this.map(function (x) {

@@ -108,0 +104,0 @@ return f.apply(null, x);

@@ -7,3 +7,3 @@ {

"keywords": ["promises", "monad", "functor"],
"version": "0.0.2",
"version": "0.0.3",
"main": "./lib/pacta.js",

@@ -10,0 +10,0 @@ "dependencies": {},

# pacta [![Build Status](https://travis-ci.org/mudge/pacta.png?branch=master)](https://travis-ci.org/mudge/pacta)
This is an implementation of algebraic Promises in
[node.js](http://nodejs.org) having been convinced by [James
Coglan](http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/)
and [Aanand Prasad](http://aanandprasad.com/articles/negronis/).
[node.js](http://nodejs.org).
Pacta's promises can be used as the following algebraic structures:
Promises can be thought of as objects representing a value that may not have
been calculated yet (similar to the [Maybe monad][Maybe]). An obvious example
is the result of an asynchronous HTTP request: it's not clear *when*
the request will be fulfilled but it will be at some point in the future.
Having actual Promise objects representing these eventual values allows you
to compose, transform and act on them without worrying about their time or
sequence of execution.
For a worked example of this, see the
[two](https://github.com/mudge/pacta/blob/master/example/codenames.js)
[example programs](https://github.com/mudge/pacta/blob/master/example/codenames-2.js)
and [sample HTTP
client](https://github.com/mudge/pacta/blob/master/example/promised-http.js)
included in Pacta.
Pacta's promises can be used as the following algebraic structures as defined
in the [Fantasy Land
Specification](https://github.com/puffnfresh/fantasy-land):
* [Semigroups](https://github.com/puffnfresh/fantasy-land#semigroup) (through
`Promise#concat` which concatenates promises containing semigroups such as
[`Promise#concat`](#promiseconcatp) which concatenates promises containing semigroups such as
arrays and strings);
* [Monoids](https://github.com/puffnfresh/fantasy-land#monoid) (through
`Promise#empty` which returns an empty version of a promise that contains a
[`Promise#empty`](#promiseempty) which returns an empty version of a promise that contains a
monoid);
* [Functors](https://github.com/puffnfresh/fantasy-land#functor) (through
`Promise#map`);
[`Promise#map`](#promisemapf));
* [Applicative](https://github.com/puffnfresh/fantasy-land#applicative)
(through `Promise#ap` and `Promise.of`);
* [Chains](https://github.com/puffnfresh/fantasy-land#chain) (through `Promise#chain`);
(through [`Promise#ap`](#promiseapp) and [`Promise.of`](#promiseofx));
* [Chains](https://github.com/puffnfresh/fantasy-land#chain) (through [`Promise#chain`](#promisechainf));
* [Monads](https://github.com/puffnfresh/fantasy-land#monad) (through all of
the above).
Above that, Pacta also provides:
As well as above, Pacta also provides the following functions for creating and
working with Promises of lists:
* `conjoin` to concatenate promises into a list of values regardless of their
original type meaning that non-Monoid types can be combined with others
(e.g. a promise of `'foo'` can be conjoined with `[1, 2]` to produce
`['foo', 1, 2]`);
* `combine` to conjoin promises without flattening lists (e.g. combining a
promise of `[1, 2]` and `[3]` will give a promise of `[[1, 2], [3]]` instead
of `[1, 2, 3]` as it would with `concat` and `conjoin`);
* `explode` to map over a promise's value but, instead of receiving a single
value, explode the promise's value into seperate arguments:
* [`Promise#conjoin`](#promiseconjoinp) to concatenate promises into a list of
values regardless of their original type meaning that non-Monoid types can
be combined with others (e.g. a promise of `'foo'` can be conjoined with
`[1, 2]` to produce `['foo', 1, 2]`);
* [`Promise#append`](#promiseappendp) to append promises to an initial promise
of a list. This means that you can work more easily with multiple promises
of lists without joining them together (as would be done with `concat` and
`conjoin`), e.g. appending a promise of `[2, 3]` to a promise of `[1]`
results in `[1, [2, 3]]` rather than `[1, 2, 3]`);
* [`Promise#spread`](#promisespreadf) to map over a promise's value but,
instead of receiving a single value, spread the promise's value across
separate arguments:
```javascript
Promise.of([1, 2]).explode(function (x, y) {
Promise.of([1, 2]).spread(function (x, y) {
console.log(x); //=> 1

@@ -54,8 +73,8 @@ console.log(y); //=> 2

See the [HTTP client
example](https://github.com/mudge/pacta/blob/master/example/codenames.js) and
[the test
See [the test
suite](https://github.com/mudge/pacta/blob/master/test/pacta_test.js) for more
information.
[Maybe]: https://en.wikipedia.org/wiki/Monad_(functional_programming)#The_Maybe_monad
## Usage

@@ -84,18 +103,206 @@

p2.concat(p3).map(function (x) {
console.log(x); //=> [ 'bar', 'baz' ]
});
p2.concat(p3).map(console.log); //=> [ 'bar', 'baz' ]
p.conjoin(p2).map(function (x) {
console.log(x); //=> [ 'Foo', 'bar' ]
});
p.conjoin(p2).map(console.log); //=> [ 'Foo', 'bar' ]
p.combine(p2).map(function (x) {
console.log(x); //=> [ 'Foo', [ 'bar' ] ]
});
Promise.of([]).append(p).append(p2).map(console.log);
//=> [ 'Foo', [ 'bar' ] ]
p.combine(p2).explode(function (x, y) {
console.log(x); //=> Foo
console.log(y); //=> [ 'bar' ]
p2.append(p).explode(function (x, y) {
console.log(x); //=> 'bar'
console.log(y); //=> 'Foo'
});
```
## API Documentation
### `Promise()`
```javascript
var promise = new Promise();
```
Create a new, unfulfilled promise that will eventually be populated with a
value (through [`resolve`](#promiseresolvex)).
### `Promise.of(x)`
```javascript
var promise = Promise.of(1);
var promise = Promise.of('foo');
```
Create a new, fulfilled promise already populated with a value `x`.
### `Promise#resolve(x)`
```javascript
var promise = new Promise();
promise.resolve(5);
```
Populate a promise with the value `x` thereby resolving it.
### `Promise#map(f)`
```javascript
var promise = Promise.of(2);
promise.map(function (x) {
console.log(x);
return x * 2;
}); //=> Promise.of(4)
```
Execute a function `f` on the contents of the promise. This returns a new
promise containing the result of applying `f` to the initial promise's value.
In [Haskell](http://www.haskell.org) notation, its type signature is:
```haskell
map :: Promise a -> (a -> b) -> Promise b
```
Note that this is the primary way of acting on the value of a promise: you can
use side-effects within your given function (e.g. `console.log`) as well as
modifying the value and returning it in order to affect the returning
promise.
### `Promise#concat(p)`
```javascript
var promise = Promise.of('foo'),
promise2 = Promise.of('bar');
promise.concat(promise2); //=> Promise.of('foobar')
```
Concatenate the promise with another promise `p` into one containing both
values concatenated together. This will work for any promise containing a
semigroup (viz. a value that supports `concat`) such as `String` or `Array`.
Note that [`concat`'s usual
behaviour](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/concat)
of joining arrays, etc. applies.
Its type signature is:
```haskell
concat :: Promise a -> Promise a -> Promise a
```
See also [`Promise#conjoin`](#promiseconjoinp) and
[`Promise#append`](#promiseappendp).
### `Promise#chain(f)`
```javascript
var promise = Promise.of(2);
promise.chain(function (x) { return Promise.of(x * 2); }); //=> Promise.of(4)
```
Execute a function `f` with the value of the promise. This differs from
[`Promise#map`](#promisemapf) in that the function *must* return a promise
itself.
Its type signature is:
```haskell
chain :: Promise a -> (a -> Promise b) -> Promise b
```
### `Promise#ap(p)`
```javascript
var promise = Promise.of(function (x) { return x * 2; }),
promise2 = Promise.of(2);
promise.ap(promise2); //=> Promise.of(4)
```
On a promise containing a function, call that function with a promise `p`
containing a value.
Its type signature is:
```haskell
ap :: Promise (a -> b) -> Promise a -> Promise b
```
### `Promise#empty()`
```javascript
var promise = Promise.of('woo');
promise.empty(); //=> Promise.of('')
```
On a promise containing a monoid (viz. something with an `empty()` function on
itself or its constructor like `Array` or `String`), return a new promise with
an empty version of the initial value.
(Pacta ships with Monoid implementations for `Array` and `String` by default.)
### `Promise#conjoin(p)`
```javascript
var promise = Promise.of(1),
promise2 = Promise.of([2, 3]);
promise.conjoin(promise2); //=> Promise.of([1, 2, 3])
```
Conjoin the promise with another promise `p`, converting their values to
arrays if needed (e.g. `'foo'` into `['foo']`). This differs from
[`Promise#concat`](#promiseconcatp) which only works on promises of values
that are semigroups themselves.
All values are coerced to arrays using `[].concat`.
### `Promise#append(p)`
```javascript
var promise = Promise.of([]),
promise2 = Promise.of([1]);
promise.append(promise2); //=> Promise.of([[1]])
```
On a promise of a list, append another promise `p`'s value to it without
joining (e.g. appending `[1]` to `[]` results in `[[1]]`).
This is particularly useful when dealing with several promises containing
lists and you want to keep them separated instead of being merged into one as
would happen with [`Promise#concat`](#promiseconcatp) and
[`Promise#conjoin`](#promiseconjoinp).
### `Promise#spread(f)`
```javascript
var promise = Promise.of([1, 2]);
promise.spread(function (x, y) {
return x + y;
}); //=> Promise.of(3)
```
Similar to [`Promise#map`](#promisemapf), apply a function `f` to a promise of
a list but, instead of receiving a single argument, pass each value of the
list to the function separately.
## Acknowledgements
[James
Coglan](http://blog.jcoglan.com/2013/03/30/callbacks-are-imperative-promises-are-functional-nodes-biggest-missed-opportunity/)
and [Aanand Prasad](http://aanandprasad.com/articles/negronis/) convinced me
to explore the idea of monadic promises and [Brian McKenna's "Fantasy Land"
specification](https://github.com/puffnfresh/fantasy-land) and
[feedback](https://github.com/mudge/pacta/issues/1) were essential.
## License
Copyright © 2013 Paul Mucur.
Distributed under the MIT License.

@@ -300,9 +300,9 @@ var assert = require('assert'),

describe('#combine', function () {
it('conjoins promises without flattening lists', function (done) {
describe('#append', function () {
it('appends promises to a promise of an array', function (done) {
var p = Promise.of([1]),
p2 = Promise.of([2, 3]);
p2 = Promise.of(2);
p.combine(p2).map(function (x) {
assert.deepEqual([[1], [2, 3]], x);
p.append(p2).map(function (x) {
assert.deepEqual([1, 2], x);
done();

@@ -312,5 +312,8 @@ });

it('conjoins non-list promises', function (done) {
p.combine(p2).map(function (x) {
assert.deepEqual(['foo', 'bar'], x);
it('appends promises of arrays to arrays without joining them', function (done) {
var p = Promise.of([1]),
p2 = Promise.of([2]);
p.append(p2).map(function (x) {
assert.deepEqual([1, [2]], x);
done();

@@ -320,7 +323,10 @@ });

it('conjoins both list and non-list promises', function (done) {
var p2 = Promise.of([2, 3]);
it('can be chained without nesting arrays', function (done) {
var p = Promise.of([]),
p2 = Promise.of([1]),
p3 = Promise.of([2, 3]),
p4 = Promise.of([4]);
p.combine(p2).map(function (x) {
assert.deepEqual(['foo', [2, 3]], x);
p.append(p2).append(p3).append(p4).map(function (x) {
assert.deepEqual([[1], [2, 3], [4]], x);
done();

@@ -331,7 +337,7 @@ });

describe('#explode', function () {
describe('#spread', function () {
it('calls the given function with each value of the Promise', function (done) {
var p = Promise.of([1, 2, 3]);
p.explode(function (x, y, z) {
p.spread(function (x, y, z) {
assert.equal(1, x);

@@ -347,3 +353,3 @@ assert.equal(2, y);

p.explode(function (x, y, z) {
p.spread(function (x, y, z) {
return x + y + z;

@@ -350,0 +356,0 @@ }).map(function (x) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc