diff --git a/.eslintrc.json b/.eslintrc.json index 43225960..616ff1df 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -26,7 +26,9 @@ "camelcase": 0, "indent": 0, "func-name-matching": 0, - "no-console": 2 + "no-console": 2, + "eqeqeq": [2, "smart"], + "no-eq-null": 0 }, "overrides": [ { diff --git a/README.md b/README.md index 30d5ad7a..06066b87 100644 --- a/README.md +++ b/README.md @@ -279,20 +279,15 @@ The concrete types you will encounter throughout this documentation: #### Type classes -Some signatures contain "constrained type variables". These constraints are -expressed by means of [type classes][Guide:constraints], specifically those defined by -[Fantasy Land][FL] and verified by [Sanctuary Type Classes][Z]: - -- [**Functor**][Z:Functor] - Values which conform to the - [Fantasy Land Functor specification][FL:functor]. -- [**Bifunctor**][Z:Bifunctor] - Values which conform to the - [Fantasy Land Bifunctor specification][FL:bifunctor]. -- [**Chain**][Z:Chain] - Values which conform to the - [Fantasy Land Chain specification][FL:chain]. -- [**Apply**][Z:Apply] - Values which conform to the - [Fantasy Land Apply specification][FL:apply]. -- [**Alt**][Z:Alt] - Values which conform to the - [Fantasy Land Alt specification][FL:alt]. +Some signatures contain [constrained type variables][Guide:constraints]. +Generally, these constraints express that some value must conform to a +[Fantasy Land][FL]-specified interface. + +- **Functor** - [Fantasy Land Functor][FL:functor] conformant values. +- **Bifunctor** - [Fantasy Land Bifunctor][FL:bifunctor] conformant values. +- **Chain** - [Fantasy Land Chain][FL:chain] conformant values. +- **Apply** - [Fantasy Land Apply][FL:apply] conformant values. +- **Alt** - [Fantasy Land Alt][FL:alt] conformant values. ### Cancellation @@ -1764,13 +1759,6 @@ it is **not** the correct way to [consume a Future](#consuming-futures). [STI]: https://github.com/sanctuary-js/sanctuary-type-identifiers [FST]: https://github.com/fluture-js/fluture-sanctuary-types -[Z]: https://github.com/sanctuary-js/sanctuary-type-classes#readme -[Z:Functor]: https://github.com/sanctuary-js/sanctuary-type-classes#Functor -[Z:Bifunctor]: https://github.com/sanctuary-js/sanctuary-type-classes#Bifunctor -[Z:Chain]: https://github.com/sanctuary-js/sanctuary-type-classes#Chain -[Z:Apply]: https://github.com/sanctuary-js/sanctuary-type-classes#Apply -[Z:Alt]: https://github.com/sanctuary-js/sanctuary-type-classes#Alt - [$]: https://github.com/sanctuary-js/sanctuary-def [concurrify]: https://github.com/fluture-js/concurrify diff --git a/package.json b/package.json index f277ca20..e5d38bb3 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,6 @@ "concurrify": "^1.0.0", "denque": "^1.1.1", "sanctuary-show": "^1.0.0", - "sanctuary-type-classes": "^9.0.0", "sanctuary-type-identifiers": "^2.0.0" }, "devDependencies": { @@ -84,6 +83,7 @@ "rollup-plugin-commonjs": "^9.1.6", "rollup-plugin-node-resolve": "^3.0.0", "sanctuary-benchmark": "^1.0.0", + "sanctuary-type-classes": "^9.0.0", "typescript": "^3.0.1", "xyz": "^3.0.0" } diff --git a/rollup.config.js b/rollup.config.js index 4238f84d..55c2442e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,7 +4,6 @@ var dependencies = { 'concurrify': 'concurrify', 'denque': 'Denque', 'sanctuary-show': 'sanctuaryShow', - 'sanctuary-type-classes': 'sanctuaryTypeClasses', 'sanctuary-type-identifiers': 'sanctuaryTypeIdentifiers' }; diff --git a/src/dispatchers/alt.mjs b/src/dispatchers/alt.mjs index 43c559f5..1e08524e 100644 --- a/src/dispatchers/alt.mjs +++ b/src/dispatchers/alt.mjs @@ -1,14 +1,15 @@ -import Z from 'sanctuary-type-classes'; +import {isAlt} from '../internal/predicates'; +import {FL} from '../internal/const'; import {partial1} from '../internal/utils'; import {throwInvalidArgument} from '../internal/throw'; function alt$left(left, right){ - if(!Z.Alt.test(right)) throwInvalidArgument('alt', 1, 'be an Alt', right); - return Z.alt(left, right); + if(!isAlt(right)) throwInvalidArgument('alt', 1, 'be an Alt', right); + return left[FL.alt](right); } export function alt(left, right){ - if(!Z.Alt.test(left)) throwInvalidArgument('alt', 0, 'be an Alt', left); + if(!isAlt(left)) throwInvalidArgument('alt', 0, 'be an Alt', left); if(arguments.length === 1) return partial1(alt$left, left); return alt$left(left, right); } diff --git a/src/dispatchers/ap.mjs b/src/dispatchers/ap.mjs index f52d90b6..97acbad8 100644 --- a/src/dispatchers/ap.mjs +++ b/src/dispatchers/ap.mjs @@ -1,14 +1,15 @@ -import Z from 'sanctuary-type-classes'; +import {isApply} from '../internal/predicates'; +import {FL} from '../internal/const'; import {partial1} from '../internal/utils'; import {throwInvalidArgument} from '../internal/throw'; function ap$mval(mval, mfunc){ - if(!Z.Apply.test(mfunc)) throwInvalidArgument('Future.ap', 1, 'be an Apply', mfunc); - return Z.ap(mval, mfunc); + if(!isApply(mfunc)) throwInvalidArgument('Future.ap', 1, 'be an Apply', mfunc); + return mfunc[FL.ap](mval); } export function ap(mval, mfunc){ - if(!Z.Apply.test(mval)) throwInvalidArgument('Future.ap', 0, 'be an Apply', mval); + if(!isApply(mval)) throwInvalidArgument('Future.ap', 0, 'be an Apply', mval); if(arguments.length === 1) return partial1(ap$mval, mval); return ap$mval(mval, mfunc); } diff --git a/src/dispatchers/bimap.mjs b/src/dispatchers/bimap.mjs index 942367a9..80ca4f1b 100644 --- a/src/dispatchers/bimap.mjs +++ b/src/dispatchers/bimap.mjs @@ -1,11 +1,12 @@ -import Z from 'sanctuary-type-classes'; +import {isBifunctor} from '../internal/predicates'; +import {FL} from '../internal/const'; import {partial1, partial2} from '../internal/utils'; import {isFunction} from '../internal/predicates'; import {throwInvalidArgument} from '../internal/throw'; function bimap$lmapper$rmapper(lmapper, rmapper, m){ - if(!Z.Bifunctor.test(m)) throwInvalidArgument('Future.bimap', 2, 'be a Bifunctor', m); - return Z.bimap(lmapper, rmapper, m); + if(!isBifunctor(m)) throwInvalidArgument('Future.bimap', 2, 'be a Bifunctor', m); + return m[FL.bimap](lmapper, rmapper); } function bimap$lmapper(lmapper, rmapper, m){ diff --git a/src/dispatchers/chain.mjs b/src/dispatchers/chain.mjs index 690426b8..65d00710 100644 --- a/src/dispatchers/chain.mjs +++ b/src/dispatchers/chain.mjs @@ -1,11 +1,12 @@ -import Z from 'sanctuary-type-classes'; +import {isChain} from '../internal/predicates'; +import {FL} from '../internal/const'; import {partial1} from '../internal/utils'; import {isFunction} from '../internal/predicates'; import {throwInvalidArgument} from '../internal/throw'; function chain$chainer(chainer, m){ - if(!Z.Chain.test(m)) throwInvalidArgument('Future.chain', 1, 'be a Chain', m); - return Z.chain(chainer, m); + if(!isChain(m)) throwInvalidArgument('Future.chain', 1, 'be a Chain', m); + return m[FL.chain](chainer); } export function chain(chainer, m){ diff --git a/src/dispatchers/map.mjs b/src/dispatchers/map.mjs index 3e97b514..c4c68c9e 100644 --- a/src/dispatchers/map.mjs +++ b/src/dispatchers/map.mjs @@ -1,11 +1,12 @@ -import Z from 'sanctuary-type-classes'; +import {isFunctor} from '../internal/predicates'; +import {FL} from '../internal/const'; import {partial1} from '../internal/utils'; import {isFunction} from '../internal/predicates'; import {throwInvalidArgument} from '../internal/throw'; function map$mapper(mapper, m){ - if(!Z.Functor.test(m)) throwInvalidArgument('Future.map', 1, 'be a Functor', m); - return Z.map(mapper, m); + if(!isFunctor(m)) throwInvalidArgument('Future.map', 1, 'be a Functor', m); + return m[FL.map](mapper); } export function map(mapper, m){ diff --git a/src/internal/const.mjs b/src/internal/const.mjs index 140ede64..b8c9f8f7 100644 --- a/src/internal/const.mjs +++ b/src/internal/const.mjs @@ -1,9 +1,10 @@ export var FL = { - map: 'fantasy-land/map', + alt: 'fantasy-land/alt', + ap: 'fantasy-land/ap', bimap: 'fantasy-land/bimap', chain: 'fantasy-land/chain', chainRec: 'fantasy-land/chainRec', - ap: 'fantasy-land/ap', + map: 'fantasy-land/map', of: 'fantasy-land/of', zero: 'fantasy-land/zero' }; diff --git a/src/internal/predicates.mjs b/src/internal/predicates.mjs index 6c2bdd0f..7d5a6c68 100644 --- a/src/internal/predicates.mjs +++ b/src/internal/predicates.mjs @@ -1,9 +1,11 @@ +import {FL} from './const'; + export function isFunction(f){ return typeof f === 'function'; } export function isThenable(m){ - return m instanceof Promise || Boolean(m) && isFunction(m.then); + return m instanceof Promise || m != null && isFunction(m.then); } export function isBoolean(f){ @@ -29,3 +31,27 @@ export function isIterator(i){ export function isArray(x){ return Array.isArray(x); } + +export function hasMethod(method, x){ + return x != null && isFunction(x[method]); +} + +export function isFunctor(x){ + return hasMethod(FL.map, x); +} + +export function isAlt(x){ + return isFunctor(x) && hasMethod(FL.alt, x); +} + +export function isApply(x){ + return isFunctor(x) && hasMethod(FL.ap, x); +} + +export function isBifunctor(x){ + return isFunctor(x) && hasMethod(FL.bimap, x); +} + +export function isChain(x){ + return isApply(x) && hasMethod(FL.chain, x); +}