Skip to content

Commit

Permalink
Merge 1eb3e8f into e2f5510
Browse files Browse the repository at this point in the history
  • Loading branch information
briancavalier committed Nov 11, 2016
2 parents e2f5510 + 1eb3e8f commit 35ba035
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ experiments/
node_modules/
coverage/
perf/logs/
.nyc_output/
19 changes: 14 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Join the chat at https://gitter.im/briancavalier/creed](https://badges.gitter.im/briancavalier/creed.svg)](https://gitter.im/briancavalier/creed?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)

Sophisticated and functionally-minded async with advanced features: coroutines, promises, ES2015 iterables, [fantasy-land](https://github.com/fantasyland/fantasy-land).
Sophisticated and functionally-minded async with advanced features: coroutines, promises, ES2015 iterables, [fantasy-land](#fantasy-land).

Creed simplifies async by letting you write coroutines using ES2015 generators and promises, and encourages functional programming via fantasy-land. It also makes uncaught errors obvious by default, and supports other ES2015 features such as iterables.

Expand Down Expand Up @@ -451,7 +451,6 @@ reject(new Error('oops!'))

### .map :: Promise e a → (a → b) → Promise e b

[Fantasy-land Functor](https://github.com/fantasyland/fantasy-land#functor).
Transform a promise's value by applying a function. The return
value of the function will be used verbatim, even if it is a promise.
Returns a new promise for the transformed value.
Expand All @@ -466,7 +465,6 @@ resolve(1)

### .ap :: Promise e (a → b) → Promise e a → Promise e b

[Fantasy-land Apply](https://github.com/fantasyland/fantasy-land#apply).
Apply a promised function to a promised value. Returns a new promise
for the result.

Expand All @@ -485,7 +483,6 @@ resolve(x => y => x+y)

### .chain :: Promise e a → (a → Promise e b) → Promise e b

[Fantasy-land Chain](https://github.com/fantasyland/fantasy-land#chain).
Sequence async actions. When a promise fulfills, run another
async action and return a promise for its result.

Expand All @@ -498,7 +495,6 @@ profileText.then(text => console.log(text)); //=> <user profile text>

### .concat :: Promise e a &rarr; Promise e a &rarr; Promise e a

[Fantasy-land Semigroup](https://github.com/fantasyland/fantasy-land#semigroup).
Returns a promise equivalent to the *earlier* of two promises. Preference is given to the callee promise in the case that both promises have already settled.

```js
Expand Down Expand Up @@ -760,3 +756,16 @@ let NativePromise = shim();
// Create a creed promise
Promise.resolve(123);
```

## Fantasy Land

Creed implements Fantasy Land 2.0:

* [Functor](https://github.com/fantasyland/fantasy-land#functor)
* [Apply](https://github.com/fantasyland/fantasy-land#apply)
* [Applicative](https://github.com/fantasyland/fantasy-land#applicative)
* [Chain](https://github.com/fantasyland/fantasy-land#chain)
* [Monad](https://github.com/fantasyland/fantasy-land#monad)
* [Semigroup](https://github.com/fantasyland/fantasy-land#semigroup)
* [Monoid](https://github.com/fantasyland/fantasy-land#monoid)

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@
"rollup": "^0.36.3",
"rollup-plugin-buble": "^0.14.0",
"uglify-js": "^2.7.3"
},
"dependencies": {
"fantasy-land": "^2.0.0"
}
}
29 changes: 28 additions & 1 deletion src/Promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import Race from './Race'
import Merge from './Merge'
import { resolveIterable, resultsArray } from './iterable'

import fl from 'fantasy-land'

const taskQueue = new TaskQueue()
export { taskQueue }

Expand All @@ -25,7 +27,8 @@ const errorHandler = new ErrorHandler(makeEmitError(), e => {
// ## Types
// -------------------------------------------------------------

// Internal base type to hold fantasy-land static constructors
// Internal base type, provides fantasy-land namespace
// and type representative
class Core {
// empty :: Promise e a
static empty () {
Expand All @@ -36,6 +39,30 @@ class Core {
static of (x) {
return fulfill(x)
}

static [fl.empty] () {
return never()
}

static [fl.of] (x) {
return fulfill(x)
}

[fl.map] (f) {
return this.map(f)
}

[fl.ap] (pf) {
return pf.ap(this)
}

[fl.chain] (f) {
return this.chain(f)
}

[fl.concat] (p) {
return this.concat(p)
}
}

// data Promise e a where
Expand Down
92 changes: 92 additions & 0 deletions test/fantasyland-laws-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { describe, it } from 'mocha'
import { fulfill, Promise } from '../src/main'
import { assertSame } from './lib/test-util'
import * as Functor from 'fantasy-land/laws/functor'
import * as Chain from 'fantasy-land/laws/chain'
import * as Apply from 'fantasy-land/laws/apply'
import * as Applicative from 'fantasy-land/laws/applicative'
import * as Semigroup from 'fantasy-land/laws/semigroup'
import * as Monoid from 'fantasy-land/laws/monoid'
import fl from 'fantasy-land'

const id = x => x

describe('fantasyland laws', () => {
describe('functor', () => {
it('should satisfy identity', () => {
return Functor.identity(fulfill, assertSame, {})
})

it('should satisfy composition', () => {
const f = x => x + 'f'
const g = x => x + 'g'
return Functor.composition(fulfill, assertSame, f, g, 'x')
})

it('should be covered', () => {
return fulfill()[fl.map](id)
})
})

describe('apply', () => {
it('should satisfy composition', () => {
return Apply.composition(fulfill, assertSame, {})
})

it('should be covered', () => {
return fulfill()[fl.ap](fulfill(id))
})
})

describe('applicative', () => {
it('should satisfy identity', () => {
return Applicative.identity(Promise, assertSame, {})
})

it('should satisfy homomorphism', () => {
return Applicative.homomorphism(Promise, assertSame, {})
})

it('should satisfy interchange', () => {
return Applicative.interchange(Promise, assertSame, {})
})

it('should be covered', () => {
return Promise[fl.of](undefined)
})
})

describe('chain', () => {
it('should satisfy associativity', () => {
return Chain.associativity(fulfill, assertSame, {})
})

it('should be covered', () => {
return fulfill()[fl.chain](fulfill)
})
})

describe('semigroup', () => {
it('should satisfy associativity', () => {
return Semigroup.associativity(fulfill, assertSame, {})
})

it('should be covered', () => {
return fulfill()[fl.concat](fulfill())
})
})

describe('monoid', () => {
it('should satisfy rightIdentity', () => {
return Monoid.rightIdentity(Promise, assertSame, {})
})

it('should satisfy leftIdentity', () => {
return Monoid.leftIdentity(Promise, assertSame, {})
})

it('should be covered', () => {
return Promise[fl.empty]().concat(fulfill())
})
})
})

0 comments on commit 35ba035

Please sign in to comment.