Skip to content

Commit

Permalink
feat(tagged): add @typed-f/tagged package (#2)
Browse files Browse the repository at this point in the history
* init(package): add @typed-f/tagged package

* refactor(tagged): rename and remove type parameters

* feat(package): update packages to use @typed-f/tagged package
  • Loading branch information
Ailrun committed Aug 14, 2018
1 parent 5785c95 commit 91b914d
Show file tree
Hide file tree
Showing 19 changed files with 300 additions and 91 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ Well typed FP utilities for TypeScript
- @typed-f/functor
- @typed-f/applicative
- @typed-f/monad
- @typed-f/tagged
1 change: 1 addition & 0 deletions config/commitlint/commitlint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = {
'setoid',
'matchable',
'maybe',
'tagged',
],
],
'scope-empty': [
Expand Down
24 changes: 6 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/applicative/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
},
"dependencies": {
"@typed-f/function": "^0.0.1",
"@typed-f/functor": "^0.0.1"
"@typed-f/functor": "^0.0.1",
"@typed-f/tagged": "^0.0.1"
},
"devDependencies": {
"rimraf": "^2.6.2",
Expand Down
39 changes: 21 additions & 18 deletions packages/applicative/src/Applicative.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { Fun } from '@typed-f/function';
import { Functor } from '@typed-f/functor';
import { Functor1, Functor2, Functor3, Functor4 } from '@typed-f/functor';
import * as T from '@typed-f/tagged';

export interface Applicative<T> extends Functor<T> {
interface ApplicativeBuilder<UnitType, ApType> {
unit: UnitType;
/**
* @desc
* Retype `Functor` methods
* alias of `unit`
*/
of: UnitType;

map<U>(f: Fun<[T], U>): Applicative<U>;
lift<U>(f: Fun<[T], U>): Applicative<U>;
fmap<U>(f: Fun<[T], U>): Applicative<U>;
ap: ApType;
}
type AB<U, A> = ApplicativeBuilder<U, A>;

/**
* @desc
* `Applicative` methods
*/
type A1U<Tag extends keyof T.Tag1List<any>, A0> = Fun<[A0], T.Tag1List<A0>[Tag]>;
type A2U<Tag extends keyof T.Tag2List<any, any>, A0, A1> = Fun<[A1], T.Tag2List<A0, A1>[Tag]>;
type A3U<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> = Fun<[A2], T.Tag3List<A0, A1, A2>[Tag]>;
type A4U<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> = Fun<[A3], T.Tag4List<A0, A1, A2, A3>[Tag]>;

unit(arg: T): Applicative<T>;
/**
* @desc
* alias of `unit`
*/
of(arg: T): Applicative<T>;
type A1A<Tag extends keyof T.Tag1List<any>, A0> = <R>(wf: T.Tag1List<Fun<[A0], R>>[Tag]) => T.Tag1List<R>[Tag];
type A2A<Tag extends keyof T.Tag2List<any, any>, A0, A1> = <R>(wf: T.Tag2List<A0, Fun<[A1], R>>[Tag]) => T.Tag2List<A0, R>[Tag];
type A3A<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> = <R>(wf: T.Tag3List<A0, A1, Fun<[A2], R>>[Tag]) => T.Tag3List<A0, A1, R>[Tag];
type A4A<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> = <R>(wf: T.Tag4List<A0, A1, A2, Fun<[A3], R>>[Tag]) => T.Tag4List<A0, A1, A2, R>[Tag];

ap<U>(wf: Applicative<Fun<[T], U>>): Applicative<U>;
}
export interface Applicative1<Tag extends keyof T.Tag1List<any>, A0> extends Functor1<Tag, A0>, AB<A1U<Tag, A0>, A1A<Tag, A0>> {}
export interface Applicative2<Tag extends keyof T.Tag2List<any, any>, A0, A1> extends Functor2<Tag, A0, A1>, AB<A2U<Tag, A0, A1>, A2A<Tag, A0, A1>> {}
export interface Applicative3<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> extends Functor3<Tag, A0, A1, A2>, AB<A3U<Tag, A0, A1, A2>, A3A<Tag, A0, A1, A2>> {}
export interface Applicative4<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> extends Functor4<Tag, A0, A1, A2, A3>, AB<A4U<Tag, A0, A1, A2, A3>, A4A<Tag, A0, A1, A2, A3>> {}
3 changes: 2 additions & 1 deletion packages/functor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
"watch": "tsc -w -p ./tsconfig.json"
},
"dependencies": {
"@typed-f/function": "^0.0.1"
"@typed-f/function": "^0.0.1",
"@typed-f/tagged": "^0.0.1"
},
"devDependencies": {
"rimraf": "^2.6.2",
Expand Down
47 changes: 38 additions & 9 deletions packages/functor/src/Functor.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,49 @@
import { Fun } from '@typed-f/function';
import * as T from '@typed-f/tagged';

export interface Functor<T> {
/**
* @desc
* `Functor` methods
*/

map<U>(f: Fun<[T], U>): Functor<U>;
interface FunctorBuilder<MapType> {
map: MapType;
/**
* @desc
* alias of `map`
*/
lift<U>(f: Fun<[T], U>): Functor<U>;
lift: MapType;
/**
* @desc
* alias of `map`
*/
fmap<U>(f: Fun<[T], U>): Functor<U>;
fmap: MapType;
}
type FB<M> = FunctorBuilder<M>;

type F1M<Tag extends keyof T.Tag1List<any>, A0> = <R>(
f: Fun<[A0], R>,
) => T.Tag1List<R>[Tag];
type F2M<Tag extends keyof T.Tag2List<any, any>, A0, A1> = <R>(
f: Fun<[A1], R>,
) => T.Tag2List<A0, R>[Tag];
type F3M<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> = <R>(
f: Fun<[A2], R>,
) => T.Tag3List<A0, A1, R>[Tag];
type F4M<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> = <R>(
f: Fun<[A3], R>,
) => T.Tag4List<A0, A1, A2, R>[Tag];

export interface Functor1<Tag extends keyof T.Tag1List<any>, A0> extends T.Tagged<Tag>, FB<F1M<Tag, A0>> {}
export interface Functor2<Tag extends keyof T.Tag2List<any, any>, A0, A1> extends T.Tagged<Tag>, FB<F2M<Tag, A0, A1>> {}
export interface Functor3<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> extends T.Tagged<Tag>, FB<F3M<Tag, A0, A1, A2>> {}
export interface Functor4<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> extends T.Tagged<Tag>, FB<F4M<Tag, A0, A1, A2, A3>> {}

export namespace Functor {
export function map<T, U>(f: Fun<[T], U>): <Tag extends keyof T.Tag1List<any>>(
wa: Functor1<Tag, T>,
) => T.Tag1List<U>[Tag] {
return function (wa) {
if ('map' in wa) {
return (wa as any).map(f);
}

throw new Error('Parameter is not a functor. You cannot call the function map with non-functor.');
}
}
}
3 changes: 2 additions & 1 deletion packages/maybe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
"@typed-f/function": "^0.0.1",
"@typed-f/matchable": "^0.0.1",
"@typed-f/monad": "^0.0.1",
"@typed-f/setoid": "^0.0.1"
"@typed-f/setoid": "^0.0.1",
"@typed-f/tagged": "^0.0.1"
},
"devDependencies": {
"rimraf": "^2.6.2",
Expand Down
24 changes: 17 additions & 7 deletions packages/maybe/src/Maybe.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
import { Fun } from '@typed-f/function';
import { MatchPatterns, Matchable } from '@typed-f/matchable';
import { Monad } from '@typed-f/monad';
import { Setoid } from '@typed-f/setoid';
import { Monad1 } from '@typed-f/monad';
import { Setoid1 } from '@typed-f/setoid';

type MaybeTag = '__typed_f__Maybe__';
const MaybeTag: MaybeTag = '__typed_f__Maybe__';

declare module '@typed-f/tagged' {
export interface Tag1List<T> {
[MaybeTag]: Maybe<T>;
}
}

export interface MaybePatterns<T, U> extends MatchPatterns<U> {
just(v: T): U;
nothing(): U;
}

abstract class BaseMaybe<T> implements Matchable, Setoid<T>, Monad<T> {
abstract class BaseMaybe<T> implements Matchable, Setoid1<MaybeTag>, Monad1<MaybeTag, T> {
public __typed_f__tag__: MaybeTag = MaybeTag;
protected abstract _kind: Maybe.Kind;

public abstract isJust(): this is Just<T>;
Expand All @@ -18,13 +28,13 @@ abstract class BaseMaybe<T> implements Matchable, Setoid<T>, Monad<T> {
public abstract valueOrCompute(f: Fun<[], T>): T;

public abstract matchWith<U>(cases: MaybePatterns<T, U>): U;
public abstract equals<U>(other: Maybe<U>): boolean;
public abstract equals(other: Maybe<any>): boolean;
public abstract map<U>(f: Fun<[T], U>): Maybe<U>;
public abstract ap<U>(f: Maybe<Fun<[T], U>>): Maybe<U>;
public abstract bind<U>(f: Fun<[T], Maybe<U>>): Maybe<U>;

public caseOf = this.matchWith;
public notEquals<U>(other: Maybe<U>): boolean {
public notEquals(other: Maybe<any>): boolean {
return !this.equals(other);
}
public lift = this.map;
Expand Down Expand Up @@ -58,7 +68,7 @@ export class Nothing<T> extends BaseMaybe<T> {
public matchWith<U>(cases: MaybePatterns<T, U>): U {
return cases.nothing();
}
public equals<U>(other: Maybe<U>): boolean {
public equals(other: Maybe<any>): boolean {
return other instanceof BaseMaybe && other.isNothing();
}

Expand Down Expand Up @@ -109,7 +119,7 @@ export class Just<T> extends BaseMaybe<T> {
* @todo
* Should be tested with something like `Maybe<Maybe<number>>`
*/
public equals<U>(other: Maybe<U>): boolean {
public equals(other: Maybe<any>): boolean {
if (!(other instanceof BaseMaybe) ||
!other.isJust()) {
return false;
Expand Down
3 changes: 2 additions & 1 deletion packages/monad/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
},
"dependencies": {
"@typed-f/applicative": "^0.0.1",
"@typed-f/function": "^0.0.1"
"@typed-f/function": "^0.0.1",
"@typed-f/tagged": "^0.0.1"
},
"devDependencies": {
"rimraf": "^2.6.2",
Expand Down
44 changes: 16 additions & 28 deletions packages/monad/src/Monad.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,23 @@
import { Applicative } from '@typed-f/applicative';
import { Applicative1, Applicative2, Applicative3, Applicative4 } from '@typed-f/applicative';
import { Fun } from '@typed-f/function';
import * as T from '@typed-f/tagged';

export interface Monad<T> extends Applicative<T> {
/**
* @desc
* Retype `Functor` methods
*/

map<U>(f: Fun<[T], U>): Monad<U>;
lift<U>(f: Fun<[T], U>): Monad<U>;
fmap<U>(f: Fun<[T], U>): Monad<U>;

/**
* @desc
* Retype `Functor` methods
*/

unit(arg: T): Monad<T>;
of(arg: T): Monad<T>;

ap<U>(wf: Monad<Fun<[T], U>>): Monad<U>;

/**
* @desc
* `Monad` methods
*/

bind<U>(wf: Fun<[T], Monad<U>>): Monad<U>;
interface MonadBuilder<BindType> {
bind: BindType;
/**
* @desc
* alias of `bind`
*/
chain<U>(wf: Fun<[T], Monad<U>>): Monad<U>;
chain: BindType;
}
type MB<B> = MonadBuilder<B>;

type M1B<Tag extends keyof T.Tag1List<any>, A0> = <R>(wf: Fun<[A0], T.Tag1List<R>[Tag]>) => T.Tag1List<R>[Tag];
type M2B<Tag extends keyof T.Tag2List<any, any>, A0, A1> = <R>(wf: Fun<[A1], T.Tag2List<A0, R>[Tag]>) => T.Tag2List<A0, R>[Tag];
type M3B<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> = <R>(wf: Fun<[A2], T.Tag3List<A0, A1, R>[Tag]>) => T.Tag3List<A0, A1, R>[Tag];
type M4B<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> = <R>(wf: Fun<[A3], T.Tag4List<A0, A1, A2, R>[Tag]>) => T.Tag4List<A0, A1, A2, R>[Tag];

export interface Monad1<Tag extends keyof T.Tag1List<any>, A0> extends Applicative1<Tag, A0>, MB<M1B<Tag, A0>> {}
export interface Monad2<Tag extends keyof T.Tag2List<any, any>, A0, A1> extends Applicative2<Tag, A0, A1>, MB<M2B<Tag, A0, A1>> {}
export interface Monad3<Tag extends keyof T.Tag3List<any, any, any>, A0, A1, A2> extends Applicative3<Tag, A0, A1, A2>, MB<M3B<Tag, A0, A1, A2>> {}
export interface Monad4<Tag extends keyof T.Tag4List<any, any, any, any>, A0, A1, A2, A3> extends Applicative4<Tag, A0, A1, A2, A3>, MB<M4B<Tag, A0, A1, A2, A3>> {}
3 changes: 3 additions & 0 deletions packages/setoid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"build": "tsc -p ./tsconfig.json",
"watch": "tsc -w -p ./tsconfig.json"
},
"dependencies": {
"@typed-f/tagged": "^0.0.1"
},
"devDependencies": {
"rimraf": "^2.6.2",
"typescript": "^3.0.1"
Expand Down

0 comments on commit 91b914d

Please sign in to comment.