Skip to content

Commit

Permalink
Drop support for "primitive" dispatching
Browse files Browse the repository at this point in the history
A while ago, I added sanctuary-type-classes as a dependency to Fluture,
primarily to gain its fantastic toString implementation. As a
side-effect, Fluture got to use its dispatcher implementations for ap,
map, bimap, chain, and alt.

Now that sanctuary-show has the toString logic, there is little to gain
from including the entirety of sanctuary-type-classes for dispatching
to FL methods.

The gains were:

- Some of its logic did not have to be reimplemented. Though as shown
  by this diff, not that much.
- Fluture dispatchers could be used on primitive types
  (like Fluture.map(f, [1, 2, 3])). I believe this functionality was
  rarely, if ever, used. Furthermore, TypeScript users were unable to
  use it out of the box because of the limitations of TypeScript.

The losses however:

- A fairly big increase of the bundle size, which as of recent I have
  been working to reduce.
- A minor hit on the performance of these dispatchers.
- The management cost of an additional dependency.
- Breaking changes to sanctuary-type-classes primitive dispatching would
  propagate to a breaking change in Fluture which was confusing to users
  (see https://git.io/fAGsJ#issuecomment-355616168 for example).
  • Loading branch information
Avaq committed Aug 29, 2018
1 parent 7130b91 commit eecc560
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 42 deletions.
30 changes: 9 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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"
}
Expand Down
1 change: 0 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ var dependencies = {
'concurrify': 'concurrify',
'denque': 'Denque',
'sanctuary-show': 'sanctuaryShow',
'sanctuary-type-classes': 'sanctuaryTypeClasses',
'sanctuary-type-identifiers': 'sanctuaryTypeIdentifiers'
};

Expand Down
9 changes: 5 additions & 4 deletions src/dispatchers/alt.mjs
Original file line number Diff line number Diff line change
@@ -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);
}
9 changes: 5 additions & 4 deletions src/dispatchers/ap.mjs
Original file line number Diff line number Diff line change
@@ -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);
}
7 changes: 4 additions & 3 deletions src/dispatchers/bimap.mjs
Original file line number Diff line number Diff line change
@@ -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){
Expand Down
7 changes: 4 additions & 3 deletions src/dispatchers/chain.mjs
Original file line number Diff line number Diff line change
@@ -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){
Expand Down
7 changes: 4 additions & 3 deletions src/dispatchers/map.mjs
Original file line number Diff line number Diff line change
@@ -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){
Expand Down
5 changes: 3 additions & 2 deletions src/internal/const.mjs
Original file line number Diff line number Diff line change
@@ -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'
};
Expand Down
26 changes: 26 additions & 0 deletions src/internal/predicates.mjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {FL} from './const';

export function isFunction(f){
return typeof f === 'function';
}
Expand Down Expand Up @@ -29,3 +31,27 @@ export function isIterator(i){
export function isArray(x){
return Array.isArray(x);
}

export function hasMethod(method, x){
return Boolean(x) && typeof x[method] === 'function';
}

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);
}

0 comments on commit eecc560

Please sign in to comment.