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 adc6461
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 21 deletions.
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 adc6461

Please sign in to comment.