Skip to content
This repository was archived by the owner on May 3, 2021. It is now read-only.

Commit 684e3e5

Browse files
committed
feat: initial commit
0 parents  commit 684e3e5

17 files changed

+958
-0
lines changed

.gitignore

Whitespace-only changes.

.vscode/settings.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"deno.enable": true,
3+
"editor.formatOnSave": true
4+
}

LICENSE

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2018 Tom Crockett
4+
Copyright (c) 2019 Brandon Blaylock
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+

README.md

Whitespace-only changes.

either.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
2+
3+
import * as E from "./either.ts";
4+
5+
// left
6+
// right
7+
// fold
8+
// isLeft
9+
// isRight
10+
// Monad
11+
// Foldable
12+
// Traversable

either.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { _0, _1 } from "./hkts.ts";
2+
import * as SL from "./type-classes.ts";
3+
4+
/***************************************************************************************************
5+
* @section Types
6+
**************************************************************************************************/
7+
8+
export type Left<L> = { tag: "Left"; left: L };
9+
export type Right<R> = { tag: "Right"; right: R };
10+
export type Either<L, R> = Left<L> | Right<R>;
11+
12+
/***************************************************************************************************
13+
* @section Constructors
14+
**************************************************************************************************/
15+
16+
export const left = <L>(left: L): Left<L> => ({ tag: "Left", left });
17+
export const right = <R>(right: R): Right<R> => ({ tag: "Right", right });
18+
19+
/***************************************************************************************************
20+
* @section Destructors
21+
**************************************************************************************************/
22+
23+
export const fold = <L, R, B>(
24+
onLeft: (left: L) => B,
25+
onRight: (right: R) => B
26+
) => (ma: Either<L, R>): B => {
27+
switch (ma.tag) {
28+
case "Left":
29+
return onLeft(ma.left);
30+
case "Right":
31+
return onRight(ma.right);
32+
}
33+
};
34+
35+
/***************************************************************************************************
36+
* @section Guards
37+
**************************************************************************************************/
38+
39+
export const isLeft = <L, R>(m: Either<L, R>): m is Left<L> => m.tag === "Left";
40+
export const isRight = <L, R>(m: Either<L, R>): m is Right<R> =>
41+
m.tag === "Right";
42+
43+
/***************************************************************************************************
44+
* @section Instances
45+
**************************************************************************************************/
46+
47+
export const Monad = SL.createMonad2<Either<_0, _1>>({
48+
of: (a) => right(a),
49+
map: (fab, ta) => (isRight(ta) ? right(fab(ta.right)) : ta),
50+
join: (tta) => (isRight(tta) ? tta.right : tta),
51+
});
52+
53+
export const Foldable: SL.Foldable2<Either<_0, _1>> = {
54+
reduce: (faba, a, tb) => (isRight(tb) ? faba(a, tb.right) : a),
55+
};
56+
57+
export const Traversable: SL.Traversable2<Either<_0, _1>> = {
58+
map: Monad.map,
59+
reduce: Foldable.reduce,
60+
traverse: (F, faub, ta) =>
61+
isLeft(ta) ? F.of(left(ta.left)) : F.map(right, faub(ta.right)),
62+
};

fns.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
2+
3+
import { compose, constant, flip, identity } from "./fns.ts";
4+
5+
const a = {};
6+
const add = (a: number) => (b: number) => a + b;
7+
const addOne = add(1);
8+
const addTwo = add(2);
9+
10+
Deno.test("identity", () => {
11+
assertEquals(identity(a), a);
12+
});
13+
14+
Deno.test("flip", () => {
15+
assertEquals(flip(add)(1)(2), flip(add)(2)(1));
16+
});
17+
18+
Deno.test("compose", () => {
19+
assertEquals(compose(addOne)(addTwo)(0), 3);
20+
});
21+
22+
Deno.test("constant", () => {
23+
assertEquals(constant(a)(), a);
24+
});

fns.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/***************************************************************************************************
2+
* @section Types
3+
**************************************************************************************************/
4+
5+
export type Fn<AS extends unknown[], B> = (...as: AS) => B;
6+
7+
/***************************************************************************************************
8+
* @section Functions
9+
**************************************************************************************************/
10+
11+
export const curry2 = <A, B, C>(fn: (a: A, b: B) => C) => (a: A) => (b: B): C =>
12+
fn(a, b);
13+
export const curry3 = <A, B, C, D>(fn: (a: A, b: B, c: C) => D) => (a: A) => (
14+
b: B
15+
) => (c: C): D => fn(a, b, c);
16+
17+
export const identity = <A>(a: A): A => a;
18+
19+
export const flip = <A, B, C>(f: (a: A) => (b: B) => C) => (b: B) => (
20+
a: A
21+
): C => f(a)(b);
22+
23+
export const compose = <A, B>(fab: (a: A) => B) => <C>(fbc: (b: B) => C) => (
24+
a: A
25+
): C => fbc(fab(a));
26+
27+
export const constant = <A>(a: A) => () => a;

hkts.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/***************************************************************************************************
2+
* @section Hole Types
3+
* @description Marks a type hole to be filled by the substitution ($) type
4+
**************************************************************************************************/
5+
6+
declare const index: unique symbol;
7+
8+
export interface _<N extends number = 0> {
9+
[index]: N;
10+
}
11+
export type _0 = _<0>;
12+
export type _1 = _<1>;
13+
export type _2 = _<2>;
14+
export type _3 = _<3>;
15+
export type _4 = _<4>;
16+
export type _5 = _<5>;
17+
export type _6 = _<6>;
18+
export type _7 = _<7>;
19+
export type _8 = _<8>;
20+
export type _9 = _<9>;
21+
22+
/***************************************************************************************************
23+
* @section Fixed Type
24+
* @description Fixes a type so it is not replaced by the substitution ($) type
25+
**************************************************************************************************/
26+
27+
declare const fixed: unique symbol;
28+
29+
export interface Fixed<T> {
30+
[fixed]: T;
31+
}
32+
33+
/***************************************************************************************************
34+
* @section Substitution Type
35+
* @description Replaces any type holes in a type with the supplied parameters
36+
* @example
37+
* type FunctorFn<T> = <A, B>(fab: (a: A) => B, ta: $<T, [A]>) => $<T, [B]>;
38+
* type ArrayInstance = FunctorFn<Array<_>>;
39+
* // ArrayInstance = <A, B>(fab: (a: A) => B, ta: A[]): B[]
40+
* type RecordInstance = FunctorFn<{ value: _ }>;
41+
* // PromiseInstance = <A, B>(fab: (a: A) => B, ta: { value: A }): { value: B }
42+
**************************************************************************************************/
43+
44+
// prettier-ignore
45+
export type $<T, S extends any[]> = (
46+
T extends Fixed<infer U> ? U :
47+
T extends _<infer N> ? S[N] :
48+
T extends any[] ? { [K in keyof T]: $<T[K], S> } :
49+
T extends (...x: infer I) => infer O ? (...x: $<I, S>) => $<O, S> :
50+
T extends object ? { [K in keyof T]: $<T[K], S> } :
51+
T extends undefined | null | boolean | string | number ? T :
52+
T
53+
);

option.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
2+
3+
import * as O from "./option.ts";
4+
5+
const addOne = (n: number) => n + 1;
6+
const someAddOne = O.some(addOne);
7+
const someNumber = O.some(2);
8+
const someOtherNumber = O.some(3);
9+
const onSome = addOne;
10+
const onNone = () => 100;

0 commit comments

Comments
 (0)