├── .gitignore
├── .babelrc
├── src
├── comonad.js
├── alternative.js
├── category.js
├── monad.js
├── semigroupoid.js
├── contravariant.js
├── plus.js
├── biapplicative.js
├── alt.js
├── monoid.js
├── semigroup.js
├── applicative.js
├── functor.js
├── bifunctor.js
├── chain.js
├── extend.js
├── setoid.js
├── chainRec.js
├── foldable.js
├── biapply.js
├── profunctor.js
├── apply.js
├── traversable.js
└── ord.js
├── README.md
├── LICENSE
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | index.js
3 | *.swp
4 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "env", {
4 | "targets": {
5 | "node": "current"
6 | },
7 | "useBuiltIns": true
8 | }]
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/comonad.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Extend } from './functor';
5 |
6 | protocol Comonad extends Extend {
7 | // extract :: Comonad w => w a ~> () -> a
8 | extract;
9 | }
10 |
11 | const extract = comonad => comonad[Comonad.extract]();
12 |
13 | export { Comonad, extract };
14 |
--------------------------------------------------------------------------------
/src/alternative.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Plus } from './plus';
5 | import { Applicative } from './applicative';
6 |
7 | protocol Alternative extends Applicative, Plus {}
8 |
9 | Reflect.implement(Array, Alternative);
10 | Reflect.implement(Object, Alternative);
11 |
12 | export { Alternative };
13 |
--------------------------------------------------------------------------------
/src/category.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Semigroupoid } from './semigroupoid';
5 |
6 | protocol Category extends Semigroupoid {
7 | static id;
8 | }
9 |
10 | Function[Category.id] = x => x;
11 | Reflect.implement(Function, Category);
12 |
13 | const id = typeRep => typeRep[Category.id];
14 |
15 | export { Category, id };
16 |
--------------------------------------------------------------------------------
/src/monad.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { Chain } from './chain';
6 |
7 | protocol Monad extends Applicative, Chain {
8 | [Functor.map](f) {
9 | return this[Chain.chain](a => this.constructor[Applicative.of](f(a)));
10 | }
11 | }
12 |
13 | Reflect.implement(Array, Monad);
14 | Reflect.implement(Function, Monad);
15 |
16 | export { Monad };
17 |
--------------------------------------------------------------------------------
/src/semigroupoid.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 |
5 | protocol Semigroupoid {
6 | // compose :: Semigroupoid c => c i j ~> c j k -> c i k
7 | compose;
8 | }
9 |
10 | Function.prototype[Semigroupoid.compose] = function compose(g) {
11 | return x => g(this(x));
12 | };
13 | Reflect.implement(Function, Semigroupoid);
14 |
15 | const compose = (f, g) => g[Semigroupoid.compose](f);
16 |
17 | export { Semigroupoid, compose };
18 |
--------------------------------------------------------------------------------
/src/contravariant.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 |
5 | protocol Contravariant {
6 | // contramap :: Contravariant f => f a ~> (b -> a) -> f b
7 | contramap;
8 | }
9 |
10 | Function.prototype[Contravariant.contramap] = function contramap(f) {
11 | return x => this(f(x));
12 | };
13 | Reflect.implement(Function, Contravariant);
14 |
15 | const contramap = (f, contravariant) => contravariant[Contravariant.contramap](f);
16 |
17 | export { Contravariant, contramap };
18 |
--------------------------------------------------------------------------------
/src/plus.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Alt } from './alt';
5 | import { Monoid } from './monoid';
6 |
7 | protocol Plus extends Alt {
8 | // zero :: Plus f => () -> f a
9 | static zero;
10 | }
11 |
12 | Array[Plus.zero] = Array[Monoid.empty];
13 | Reflect.implement(Array, Plus);
14 |
15 | Object[Plus.zero] = Object[Monoid.empty];
16 | Reflect.implement(Object, Plus);
17 |
18 | const zero = typeRep => typeRep[Plus.zero]();
19 |
20 | export { Plus, zero };
21 |
--------------------------------------------------------------------------------
/src/biapplicative.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Bipply } from './biapply';
5 | import { Bifunctor } from './bifunctor';
6 |
7 | protocol Applicative extends Apply {
8 | // biof :: Biapplicative w => a -> b -> w a b
9 | static biof;
10 | [Bifunctor.bimap](f, g) {
11 | return this[Biapply.biap](this.constructor[Biapplicative.biof](f, g));
12 | }
13 | }
14 |
15 | const biof = typeRep => (a, b) => typeRep[Biapplicative.biof](a, b);
16 |
17 | export { Biapplicative, biof };
18 |
--------------------------------------------------------------------------------
/src/alt.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { Semigroup } from './semigroup';
6 |
7 | protocol Alt extends Functor {
8 | // alt :: Alt f => f a ~> f a -> f a
9 | alt;
10 | }
11 |
12 | Array.prototype[Alt.alt] = Array.prototype[Semigroup.concat];
13 | Reflect.implement(Array, Alt);
14 |
15 | Object.prototype[Alt.alt] = Object.prototype[Semigroup.concat];
16 | Reflect.implement(Object, Alt);
17 |
18 | const alt = (a, b) => a[Alt.alt](b);
19 |
20 | export { Alt, alt };
21 |
--------------------------------------------------------------------------------
/src/monoid.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Semigroup } from './semigroup';
5 |
6 | protocol Monoid extends Semigroup {
7 | // empty :: Monoid m => () -> m
8 | static empty;
9 | }
10 |
11 | String[Monoid.empty] = () => "";
12 | Reflect.implement(String, Monoid);
13 |
14 | Array[Monoid.empty] = () => [];
15 | Reflect.implement(Array, Monoid);
16 |
17 | Object[Monoid.empty] = () => ({});
18 | Reflect.implement(Object, Monoid);
19 |
20 | const empty = typeRep => typeRep[Monoid.empty]();
21 |
22 | export { Monoid, empty };
23 |
--------------------------------------------------------------------------------
/src/semigroup.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 |
5 | protocol Semigroup {
6 | // concat :: Semigroup a => a ~> a -> a
7 | concat(b) {
8 | return this.concat(b);
9 | }
10 | }
11 |
12 | Reflect.implement(String, Semigroup);
13 | Reflect.implement(Array, Semigroup);
14 |
15 | Object.prototype[Semigroup.concat] = function concat(b) {
16 | const result = {};
17 | let k;
18 | for (k in this) result[k] = this[k];
19 | for (k in b) result[k] = b[k];
20 | return result;
21 | };
22 | Reflect.implement(Object, Semigroup);
23 |
24 | const concat = (a, b) => a[Semigroup.concat](b);
25 |
26 | export { Semigroup, concat };
27 |
--------------------------------------------------------------------------------
/src/applicative.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Apply } from './apply';
5 | import { Functor } from './functor';
6 |
7 | protocol Applicative extends Apply {
8 | // of :: Applicative f => a -> f a
9 | static of;
10 | [Functor.map](f) {
11 | return this[Apply.ap](this.constructor[Applicative.of](f));
12 | }
13 | }
14 |
15 | Array[Applicative.of] = function of(a) {
16 | return [a];
17 | };
18 | Reflect.implement(Array, Applicative);
19 |
20 | Function[Applicative.of] = x => _ => x;
21 | Reflect.implement(Function, Applicative);
22 |
23 | const of = typeRep => v => typeRep[Applicative.of](v);
24 |
25 | export { Applicative, of };
26 |
--------------------------------------------------------------------------------
/src/functor.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 |
5 | protocol Functor {
6 | // map :: Functor f => f a ~> (a -> b) -> f b
7 | map;
8 | }
9 |
10 | Array.prototype[Functor.map] = function map(f) {
11 | return this.map(f);
12 | };
13 | Reflect.implement(Array, Functor);
14 |
15 | Object.prototype[Functor.map] = function map(f) {
16 | var result = {};
17 | for (var k in this) result[k] = f(this[k]);
18 | return result;
19 | };
20 | Reflect.implement(Object, Functor);
21 |
22 | Function.prototype[Functor.map] = function map(f) {
23 | return x => f(this(x));
24 | };
25 | Reflect.implement(Function, Functor);
26 |
27 | const map = (f, functor) => functor[Functor.map](f);
28 |
29 | export { Functor, map };
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fantasy Interfaces
2 |
3 |
4 |
5 | JavaScript "native" interfaces for Fantasy Land.
6 |
7 | It uses [sweet-interfaces](https://github.com/disnet/sweet-interfaces) to implement an extended [Fantasy Land](https://github.com/fantasyland/fantasy-land) specification.
8 |
9 | See the [ECMAScript Interfaces Proposal](https://github.com/michaelficarra/ecmascript-interfaces-proposal) for details.
10 |
11 |
12 | ## Attributions
13 |
14 |
15 |
16 | Most of the code for native types was adapted from the [Sanctuary](https://github.com/sanctuary-js/sanctuary-type-classes) project.
17 |
--------------------------------------------------------------------------------
/src/bifunctor.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { id } from './category';
6 |
7 | const identity = id(Function);
8 |
9 | protocol Bifunctor extends Functor {
10 | // bimap :: Bifunctor f => f a c ~> (a -> b, c -> d) -> f b d
11 | bimap(f, g) {
12 | return this[Bifunctor.first](f)[Bifunctor.second](g);
13 | }
14 |
15 | // first :: Bifunctor f => f a c ~> (a -> b) -> f b c
16 | first(f) {
17 | return this[Bifunctor.bimap](f, identity);
18 | }
19 |
20 | // second :: Bifunctor f => f a b ~> (b -> c) -> f a c
21 | second(f) {
22 | return this[Bifunctor.bimap](identity, f);
23 | }
24 |
25 | [Functor.map](f) { return this[Bifunctor.bimap](identity, f); }
26 | }
27 |
28 | const bimap = (f, g, bifunctor) => bifunctor[Bifunctor.bimap](f, g);
29 | const first = (f, bifunctor) => bifunctor[Bifunctor.first](f);
30 | const second = (f, bifunctor) => bifunctor[Bifunctor.second](f);
31 |
32 | export {
33 | Bifunctor,
34 | bimap,
35 | first,
36 | second,
37 | };
38 |
--------------------------------------------------------------------------------
/src/chain.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { Apply } from './apply';
6 | import { Category } from './category';
7 |
8 | protocol Chain extends Apply {
9 | // chain :: Chain m => m a ~> (a -> m b) -> m b
10 | chain(f) {
11 | return this[Chain.join]()[Functor.map](f);
12 | }
13 |
14 | // join :: Chain m => m (m a) ~> m a
15 | join() {
16 | return this[Chain.chain](Function[Category.id]);
17 | }
18 |
19 | [Apply.ap](m) {
20 | return m[Chain.chain](f => this[Functor.map](f));
21 | }
22 | }
23 |
24 | Array.prototype[Chain.chain] = function chain(f) {
25 | const result = [];
26 | this.forEach(x => Array.prototype.push.apply(result, f(x)));
27 | return result;
28 | };
29 | Reflect.implement(Array, Chain);
30 |
31 | Function.prototype[Chain.chain] = function chain(f) {
32 | return x => f(this(x))(x);
33 | };
34 | Reflect.implement(Function, Chain);
35 |
36 | const chain = (f, ch) => ch[Chain.chain](f);
37 | const join = ch => ch[Chain.join]();
38 |
39 | export {
40 | Chain,
41 | chain,
42 | join
43 | };
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Gabe Johnson
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "fantasy-interfaces",
3 | "version": "0.0.1",
4 | "description": "JavaScript \"native\" interfaces for Fantasy Land",
5 | "main": "index.js",
6 | "scripts": {
7 | "prebuild": "mkdir -p tmp dist",
8 | "build": "for file in src/*; do sjs \"$file\" --out-dir tmp/; done && babel tmp/ --out-dir dist/",
9 | "postbuild": "rm -rf tmp",
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/gabejohnson/fantasy-interfaces.git"
15 | },
16 | "keywords": [
17 | "interfaces",
18 | "macros",
19 | "sweet.js",
20 | "fantasy-land",
21 | "algebraic"
22 | ],
23 | "author": "Gabe Johnson ",
24 | "license": "MIT",
25 | "bugs": {
26 | "url": "https://github.com/gabejohnson/fantasy-interfaces/issues"
27 | },
28 | "homepage": "https://github.com/gabejohnson/fantasy-interfaces#readme",
29 | "dependencies": {
30 | "@sweet-js/cli": "^3.0.13",
31 | "sweet-interfaces": "^0.4.0"
32 | },
33 | "devDependencies": {
34 | "babel-cli": "^6.24.1",
35 | "babel-preset-env": "^1.6.0"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/extend.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { Category } from './category';
6 |
7 | protocol Extend extends Functor {
8 | // extend :: Extend w => w a ~> (w a -> b) -> w b
9 | extend(f) {
10 | return this[Extend.duplicate]()[Functor.map](f);
11 | }
12 |
13 | // duplicate :: Extend w => w a ~> w (w a)
14 | duplicate() {
15 | return this[Extend.extend](Function[Category.id]);
16 | }
17 | }
18 |
19 | Array.prototype[Extend.extend] = function extend(f) {
20 | return this.map((_, idx, xs) => f(xs.slice(idx)));
21 | };
22 | Array.prototype[Extend.duplicate] = function duplicate() {
23 | return this.map((_, idx, xs) => xs.slice(idx));
24 | };
25 | Reflect.implement(Array, Extend);
26 |
27 | Function.prototype[Extend.extend] = function extend(f) {
28 | return x => f(y => this(x.concat(y)));
29 | };
30 | Function.prototype[Extend.duplicate] = function duplicate() {
31 | return x => y => this(x.concat(y));
32 | };
33 | Reflect.implement(Function, Extend);
34 |
35 | const extend = (f, ext) => ext[Extend.extend](f);
36 | const duplicate = ext => ext[Extend.duplicate]();
37 |
38 | export {
39 | Extend,
40 | extend,
41 | duplicate
42 | };
43 |
--------------------------------------------------------------------------------
/src/setoid.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 |
5 | protocol Setoid {
6 | // equals :: Setoid a => a ~> a -> Boolean
7 | equals(b) { return this.valueOf() === b.valueOf(); }
8 | }
9 |
10 | Reflect.implement(Boolean, Setoid);
11 |
12 | Number.prototype[Setoid.equals] = function equals(b) {
13 | return this === b || isNaN(this) && isNaN(b);
14 | };
15 | Reflect.implement(Number, Setoid);
16 |
17 | Reflect.implement(Date, Setoid);
18 |
19 | Reflect.implement(String, Setoid);
20 |
21 | Error.prototype[Setoid.equals] = function equals(b) {
22 | return this.name[equals](b.name) && this.message[equals](b.message);
23 | };
24 | Reflect.implement(Error, Setoid);
25 |
26 | Array.prototype[Setoid.equals] = function equals(b) {
27 | if (b.length !== this.length) return false;
28 | for (var idx = 0; idx < this.length; idx += 1) {
29 | if (!this[idx][equals](b[idx])) return false;
30 | }
31 | return true;
32 | };
33 | Reflect.implement(Array, Setoid);
34 |
35 | Object.prototype[Setoid.equals] = function equals(b) {
36 | const keys = Object.keys(this).sort();
37 | return keys[equals](Object.keys(b).sort()) &&
38 | keys.every(k => this[k][equals](other[k]));
39 | };
40 | Reflect.implement(Object, Setoid);
41 |
42 | const equals = (a, b) => a[Setoid.equals](b);
43 |
44 | export { Setoid, equals };
45 |
--------------------------------------------------------------------------------
/src/chainRec.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Chain } from './chain';
5 |
6 | protocol ChainRec extends Chain {
7 | // chainRec :: ChainRec m => ((a -> c, b -> c, a) -> m c, a) -> m b
8 | static chainRec;
9 | }
10 |
11 | const iterate = done => value => ({ value, done });
12 | const cont = iterate(false);
13 | const stop = iterate(true);
14 |
15 | Array[ChainRec.chainRec] = function chainRec(f, x) {
16 | const remaining = [x];
17 | const complete = [];
18 | while (remaining.length > 0) {
19 | const xs = f(cont, stop, remaining.shift());
20 | const additional = [];
21 | let value, done;
22 | for (let idx = 0; idx < xs.length; idx += 1) {
23 | ({ value, done } = xs[idx]);
24 | (done ? complete : additional).push(value);
25 | }
26 | Array.prototype.unshift.apply(remaining, additional);
27 | }
28 | return complete;
29 | };
30 | Reflect.implement(Array, ChainRec);
31 |
32 | Function[ChainRec.chainRec] = function chainRec(f, x) {
33 | return a => {
34 | let { value, done } = cont(x);
35 | while (!done) ({ value, done } = f(cont, stop, value)(a));
36 | return value;
37 | };
38 | };
39 | Reflect.implement(Function, ChainRec);
40 |
41 | const chainRec = typeRep => (f, chain) => typeRep[ChainRec.chainRec](f, chain);
42 |
43 | export { ChainRec, chainRec };
44 |
--------------------------------------------------------------------------------
/src/foldable.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 |
5 | const flip = f => (a, b) => f(b, a);
6 |
7 | protocol Foldable {
8 | // reduce :: Foldable f => f a ~> ((b, a) -> b, b) -> b
9 | reduce(f, init) {
10 | this[Foldable.reduceRight](flip(f), init);
11 | }
12 |
13 | // reduceRight :: Foldable f => f a ~> ((a, b) -> b, b) -> b
14 | reduceRight(f, init) {
15 | this[Foldable.reduce](flip(f), init);
16 | }
17 |
18 | // reduceMap :: Foldable f, Monoid m => f a ~> (TypeRep m, (a -> m)) -> m
19 | reduceMap(typeRep, f) {
20 | return this[Foldable.reduce]((acc, a) => f(a)[Semigroup.concat](acc), typeRep[Monoid.empty]());
21 | }
22 | }
23 |
24 | Array.prototype[Foldable.reduce] = function reduce(f, init) {
25 | return this.reduce((acc, x) => f(acc, x), init);
26 | };
27 | Reflect.implement(Array, Foldable);
28 |
29 | Object.prototype[Foldable.reduce] = function reduce(f, init) {
30 | return Object
31 | .keys(this)
32 | .sort()
33 | .reduce((acc, k) => f(acc, this[k]), init);
34 | };
35 | Reflect.implement(Object, Foldable);
36 |
37 | const reduce = (f, init, foldable) => foldable[Foldable.reduce](f, init);
38 | const reduceRight = (f, init, foldable) => foldable[Foldable.reduceRight](f, init);
39 | const reduceMap = (typeRep, f, foldable) => foldable[Foldable.reduceMap](typeRep, f);
40 |
41 | export {
42 | Foldable
43 | reduce,
44 | reduceRight,
45 | reduceMap
46 | };
47 |
--------------------------------------------------------------------------------
/src/biapply.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Bifunctor } from './bifunctor';
5 | import { id } from './category';
6 |
7 | const identity = id(Function);
8 | const constant = k => () => k;
9 |
10 | protocol Biapply extends Bifunctor {
11 | // biap :: Biapply w => w a c ~> w (a -> b) (c -> d) -> w b d
12 | biap(w) {
13 | this.constructor[Biapply.bilift](identity, identity, w, this);
14 | }
15 |
16 | // bilift :: Biapply w => (a -> b -> ... -> c) -> (d -> e -> ... -> f) -> w a d -> w b e -> ... -> w c f
17 | static bilift(f, g, a, ...bs) {
18 | const result = a[Bifunctor.bimap](f, g);
19 | return bs.reduce((f, a) => a[Biapply.biap](f), result);
20 | }
21 |
22 | // biapFirst :: Biapply w => w a b ~> w c d -> w a b
23 | biapFirst(y) {
24 | this.constructor[Biapply.bilift](constant, constant, this, y);
25 | }
26 |
27 | // biapSecond :: Apply f => f a ~> f b -> f b
28 | biapSecond(y) {
29 | this.constructor[Biapply.bilift](constant(identity), constant(identity), this, y);
30 | }
31 | }
32 |
33 | const biap = (other, biapply) => biapply[Biapply.biap](other);
34 | const biapFirst = (other, biapply) => biapply[Biapply.biapFirst](other);
35 | const biapSecond = (other, biapply) => biapply[Biapply.biapSecond](other);
36 | const bilift = typeRep => (f, g, a, ...bs) => typeRep[Biapply.bilift](f, g, a, ...bs);
37 | export {
38 | Biapply,
39 | biap,
40 | biapFirst,
41 | biapSecond,
42 | bilift
43 | };
44 |
--------------------------------------------------------------------------------
/src/profunctor.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { id } from './category';
6 |
7 | const identity = id(Function);
8 |
9 | protocol Profunctor extends Functor {
10 | // promap :: Profunctor p => p b c ~> (a -> b, c -> d) -> p a d
11 | promap(f, g) {
12 | return this[Profunctor.lmap](f)[Profunctor.rmap](g);
13 | }
14 |
15 | // lmap :: Profunctor p => p b c ~> (a -> b) -> p a c
16 | lmap(f) {
17 | return this[Profunctor.promap](f, identity);
18 | }
19 |
20 | // rmap :: Profunctor p => p a b ~> (b -> c) -> p a c
21 | rmap(f) {
22 | return this[Profunctor.promap](identity, f);
23 | }
24 |
25 | // arr :: (Category p, Profunctor p) => (a -> b) -> p a b
26 | static arr(f) {
27 | return f[Profunctor.rmap](identity);
28 | }
29 |
30 | [Functor.map](f) {
31 | return this[Profunctor.promap](identity, f);
32 | }
33 | }
34 |
35 | Function.prototype[Profunctor.promap] = function promap(f, g) {
36 | return x => g(this(f(x)));
37 | };
38 | Function.prototype[Profunctor.lmap] = Function.prototype[Contravariant.contramap];
39 | Function.prototype[Profunctor.rmap] = Function.prototype[Functor.map];
40 |
41 | Reflect.implement(Function, Profunctor);
42 |
43 | const promap = (f, g, profunctor) => profunctor[Profunctor.promap](f, g);
44 | const lmap = (f, profunctor) => profunctor[Profunctor.lmap](f);
45 | const rmap = (f, profunctor) => profunctor[Profunctor.rmap](f);
46 | const arr = typeRep => f => typeRep[Profunctor.arr](f);
47 |
48 | export {
49 | Profunctor,
50 | promap,
51 | lmap,
52 | rmap,
53 | arr
54 | };
55 |
--------------------------------------------------------------------------------
/src/apply.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { id } from './category';
6 |
7 | const constant = k => () => k;
8 |
9 | protocol Apply extends Functor {
10 | // ap :: Apply f => f a ~> f (a -> b) -> f b
11 | ap(f) {
12 | this.constructor[Apply.lift](x => x, f, this);
13 | }
14 |
15 | // lift :: Apply f => (a -> b -> ... -> c) -> f a -> f b -> ... -> f c
16 | static lift(f, a, ...bs) {
17 | const result = a[Functor.map](f);
18 | return bs.reduce((f, a) => a[Apply.ap](f), result);
19 | }
20 |
21 | // apFirst :: Apply f => f a ~> f b -> f a
22 | apFirst(y) {
23 | this.constructor[Apply.lift](constant, this, y);
24 | }
25 |
26 | // apSecond :: Apply f => f a ~> f b -> f b
27 | apSecond(y) {
28 | this.constructor[Apply.lift](constant(id(Function)), this, y);
29 | }
30 | }
31 |
32 | Array.prototype[Apply.ap] = function ap(fs) {
33 | const result = [];
34 | for (let idx = 0; idx < fs.length; idx += 1) {
35 | for (let idx2 = 0; idx2 < this.length; idx2 += 1) {
36 | result.push(fs[idx](this[idx2]));
37 | }
38 | }
39 | return result;
40 | };
41 | Reflect.implement(Array, Apply);
42 |
43 | Object.prototype[Apply.ap] = function ap(b) {
44 | var result = {};
45 | for (let k in this) if (k in b) result[k] = b[k](this[k]);
46 | return result;
47 | };
48 | Reflect.implement(Object, Apply);
49 |
50 | Function.prototype[Apply.ap] = function ap(f) {
51 | return x => f(x)(this(x));
52 | };
53 | Reflect.implement(Function, Apply);
54 |
55 | const ap = (f, other) => other[Apply.ap](f);
56 | const apFirst = (a, b) => b[Apply.apFirst](a);
57 | const apSecond = (a, b) => b[Apply.apSecond](a);
58 | const lift = typeRep => (f, a, ...bs) => typeRep[Apply.lift](f, a, ...bs);
59 | export {
60 | Apply,
61 | ap,
62 | apFirst,
63 | apSecond,
64 | lift
65 | };
66 |
--------------------------------------------------------------------------------
/src/traversable.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { protocol, implements } from 'sweet-interfaces';
4 | import { Functor } from './functor';
5 | import { Apply, lift } from './apply';
6 | import { Applicative } from './applicative';
7 | import { Foldable } from './foldable';
8 | import { id } from './category';
9 |
10 | const identity = id(Function);
11 |
12 | protocol Traversable extends Functor, Foldable {
13 | // traverse :: Applicative f, Traversable t => t a ~> (TypeRep f, a -> f b) -> f (t b)
14 | traverse(typeRep, f) {
15 | return this[Functor.map](f).sequence(typeRep);
16 | }
17 |
18 | // sequence :: Applicative f, Traversable t => t (f a) ~> TypeRep f -> f (t a)
19 | sequence(typeRep) {
20 | return this.traverse(typeRep, identity);
21 | }
22 | }
23 |
24 | const concat = a => b => a[Semigroup.concat](b);
25 | const pair = x => y => [x, y];
26 |
27 | Array.prototype[Traversable.traverse] = function traverse(typeRep, f) {
28 | const xs = this;
29 | function go(idx, n) {
30 | switch (n) {
31 | case 0: return typeRep[Applicative.of]([]);
32 | case 2: return lift(typeRep, pair, f(xs[idx]), f(xs[idx + 1]));
33 | default:
34 | const m = Math.floor(n / 4) * 2;
35 | return lift(typeRep, concat, go(idx, m), go(idx + m, n - m));
36 | }
37 | }
38 | return this.length % 2 === 1 ?
39 | lift(concat, f(this[0])[Functor.map](Array[Applicative.of]), go(1, this.length - 1)) :
40 | go(0, this.length);
41 | };
42 | Reflect.implement(Array, Traversable);
43 |
44 | Object.prototype[Traversable.traverse] = function traverse(typeRep, f) {
45 | return Object
46 | .keys(this)
47 | .reduce((applicative, k) => lift(o => v => (o[k] = v, o), applicative, f(this[k]))
48 | , typeRep[Applicative.of]({}));
49 | };
50 | Reflect.implement(Object, Traversable);
51 |
52 | const traverse = (typeRep, f, traversable) => traversable[Traversable.traverse](typeRep, f);
53 | const sequence = (typeRep, traversable) => traversable[Traversable.sequence](typeRep);
54 |
55 | export {
56 | Traversable,
57 | traverse,
58 | sequence
59 | };
60 |
--------------------------------------------------------------------------------
/src/ord.js:
--------------------------------------------------------------------------------
1 | 'lang sweet.js';
2 |
3 | import { implements, protocol } from 'sweet-interfaces';
4 | import { Setoid } from './setoid';
5 |
6 | protocol Ord extends Setoid {
7 | // lte :: Ord a, b => a ~> b -> Boolean
8 | lte(b) { return this.valueOf() <= b.valueOf(); }
9 |
10 | // lt :: Ord a, b => a ~> b -> Boolean
11 | lt(b) { return this[Ord.lte](b) && !this[Setoid.equals](b); }
12 |
13 | // gt :: Ord a, b => a ~> b -> Boolean
14 | gt(b) { return !this[Ord.lte](b); }
15 |
16 | // gte :: Ord a, b => a ~> b -> Boolean
17 | gte(b) { return !this[Ord.lt](b); }
18 |
19 | [Setoid.equals](b) {
20 | return this[Ord.lte](b) && b[Ord.lte](this);
21 | }
22 | }
23 |
24 | Boolean.prototype[Ord.lte] = function lte(b) {
25 | return this === false || b === true;
26 | };
27 | Reflect.implement(Boolean, Ord);
28 |
29 | Number.prototype[Ord.lte] = function lte(b) {
30 | return this <= b || isNaN(this) && isNaN(b);
31 | };
32 | Reflect.implement(Number, Ord);
33 |
34 | Reflect.implement(Date, Ord);
35 |
36 | Reflect.implement(String, Ord);
37 |
38 | Error.prototype[Ord.lte] = function lte(b) {
39 | return this.name[lte](b.name) && this.message[lte](b.message);
40 | };
41 | Reflect.implement(Error, Ord);
42 |
43 | Array.prototype[Ord.lte] = function lte(b) {
44 | for (let idx = 0; true; idx += 1) {
45 | if (idx === this.length) return true;
46 | if (idx === b.length) return false;
47 | if (this[idx][Setoid.equals](b[idx])) return this[idx][lte](b[idx]);
48 | }
49 | };
50 | Reflect.implement(Array, Setoid);
51 |
52 | Object.prototype[Ord.lte] = function lte(b) {
53 | const theseKeys = Object.keys(this).sort();
54 | const otherKeys = Object.keys(b).sort();
55 | while (true) {
56 | if (theseKeys.length === 0) return true;
57 | if (otherKeys.length === 0) return false;
58 | let k = theseKeys.shift();
59 | let z = otherKeys.shift();
60 | if (k < z) return true;
61 | if (k > z) return false;
62 | if (!this[k][Setoid.equals](other[k])) return this[k][lte](b[k]);
63 | }
64 | };
65 | Reflect.implement(Object, Ord);
66 |
67 | const lte = (a, b) => a[Ord.lte](b);
68 | const lt = (a, b) => a[Ord.lt](b);
69 | const gt = (a, b) => a[Ord.gt](b);
70 | const gte = (a, b) => a[Ord.gte](b);
71 |
72 | export {
73 | Ord,
74 | lte,
75 | lt,
76 | gt,
77 | gte
78 | };
79 |
--------------------------------------------------------------------------------