This repository has been archived by the owner on May 3, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: various monads and traversables
* implemented array monad and traversable * ported decode_error from io-ts * added indexed foldable and indexed traversable type classes * added monad throw type class * implemented getRightMonad and monad throw for either * ported free semigroup from io-ts * ported schemable from io-ts * ported guard from io-ts * added refinement to $ substitution
- Loading branch information
Showing
13 changed files
with
912 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import type * as TC from "./type_classes.ts"; | ||
import type { _ } from "./hkts.ts"; | ||
|
||
import * as D from "./derivations.ts"; | ||
|
||
/*************************************************************************************************** | ||
* @section Optimizations | ||
**************************************************************************************************/ | ||
|
||
const _map = <A, B>(as: A[], fab: (a: A, i: number) => B): B[] => { | ||
const out: B[] = new Array(as.length); | ||
for (let i = 0; i < as.length; i++) { | ||
out[i] = fab(as[i], i); | ||
} | ||
return out; | ||
}; | ||
|
||
const _reduce = <A, B>( | ||
as: A[], | ||
fbab: (b: B, a: A, i: number) => B, | ||
b: B, | ||
): B => { | ||
let out = b; | ||
for (let i = 0; i < as.length; i++) { | ||
out = fbab(out, as[i], i); | ||
} | ||
return out; | ||
}; | ||
|
||
/*************************************************************************************************** | ||
* @section Modules | ||
**************************************************************************************************/ | ||
|
||
export const Monad = D.createMonad<Array<_>>({ | ||
of: (a) => [a], | ||
chain: (fatb, ta) => _map(ta, fatb).flat(), | ||
}); | ||
|
||
export const IndexedFoldable: TC.IndexedFoldable<Array<_>> = { | ||
reduce: (faba, a, tb) => _reduce(tb, (a, b, i) => faba(a, b, i), a), | ||
}; | ||
|
||
export const IndexedTraversable: TC.IndexedTraversable<Array<_>> = { | ||
map: Monad.map, | ||
reduce: IndexedFoldable.reduce, | ||
traverse: (A, faub, ta) => | ||
IndexedFoldable.reduce( | ||
(fbs, a, i) => | ||
A.ap( | ||
A.map((bs: any) => (b: any) => [...bs, b], fbs) as any, | ||
faub(a, i), | ||
), | ||
A.of([]), | ||
ta, | ||
), | ||
}; | ||
|
||
export const Foldable: TC.Foldable<Array<_>> = { | ||
reduce: (faba, a, tb) => IndexedFoldable.reduce((a, b) => faba(a, b), a, tb), | ||
}; | ||
|
||
export const Traversable: TC.Traversable<Array<_>> = { | ||
map: Monad.map, | ||
reduce: Foldable.reduce, | ||
traverse: (A, faub, ta) => IndexedTraversable.traverse(A, (a) => faub(a), ta), | ||
}; | ||
|
||
/*************************************************************************************************** | ||
* @section Pipeables | ||
**************************************************************************************************/ | ||
|
||
export const { of, ap, map, join, chain } = D.createPipeableMonad(Monad); | ||
|
||
export const { reduce, traverse } = D.createPipeableTraversable(Traversable); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
import { Semigroup } from "./type_classes.ts"; | ||
import * as FS from "./free_semigroup.ts"; | ||
|
||
/*************************************************************************************************** | ||
* @section DecodeError | ||
* @from https://raw.githubusercontent.com/gcanti/io-ts/master/src/DecodeError.ts | ||
**************************************************************************************************/ | ||
|
||
/*************************************************************************************************** | ||
* @section Types | ||
**************************************************************************************************/ | ||
|
||
export type Leaf<E> = { | ||
readonly tag: "Leaf"; | ||
readonly actual: unknown; | ||
readonly error: E; | ||
}; | ||
|
||
export const required: "required" = "required"; | ||
export const optional: "optional" = "optional"; | ||
|
||
export type Kind = "required" | "optional"; | ||
|
||
export type Key<E> = { | ||
readonly tag: "Key"; | ||
readonly key: string; | ||
readonly kind: Kind; | ||
readonly errors: FS.FreeSemigroup<DecodeError<E>>; | ||
}; | ||
|
||
export type Index<E> = { | ||
readonly tag: "Index"; | ||
readonly index: number; | ||
readonly kind: Kind; | ||
readonly errors: FS.FreeSemigroup<DecodeError<E>>; | ||
}; | ||
|
||
export type Member<E> = { | ||
readonly tag: "Member"; | ||
readonly index: number; | ||
readonly errors: FS.FreeSemigroup<DecodeError<E>>; | ||
}; | ||
|
||
export type Lazy<E> = { | ||
readonly tag: "Lazy"; | ||
readonly id: string; | ||
readonly errors: FS.FreeSemigroup<DecodeError<E>>; | ||
}; | ||
|
||
export type Wrap<E> = { | ||
readonly tag: "Wrap"; | ||
readonly error: E; | ||
readonly errors: FS.FreeSemigroup<DecodeError<E>>; | ||
}; | ||
|
||
export type DecodeError<E> = | ||
| Leaf<E> | ||
| Key<E> | ||
| Index<E> | ||
| Member<E> | ||
| Lazy<E> | ||
| Wrap<E>; | ||
|
||
/*************************************************************************************************** | ||
* @section Constructors | ||
**************************************************************************************************/ | ||
|
||
export const leaf = <E>(actual: unknown, error: E): DecodeError<E> => ({ | ||
tag: "Leaf", | ||
actual, | ||
error, | ||
}); | ||
|
||
export const key = <E>( | ||
key: string, | ||
kind: Kind, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
): DecodeError<E> => ({ | ||
tag: "Key", | ||
key, | ||
kind, | ||
errors, | ||
}); | ||
|
||
export const index = <E>( | ||
index: number, | ||
kind: Kind, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
): DecodeError<E> => ({ | ||
tag: "Index", | ||
index, | ||
kind, | ||
errors, | ||
}); | ||
|
||
export const member = <E>( | ||
index: number, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
): DecodeError<E> => ({ | ||
tag: "Member", | ||
index, | ||
errors, | ||
}); | ||
|
||
export const lazy = <E>( | ||
id: string, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
): DecodeError<E> => ({ | ||
tag: "Lazy", | ||
id, | ||
errors, | ||
}); | ||
|
||
export const wrap = <E>( | ||
error: E, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
): DecodeError<E> => ({ | ||
tag: "Wrap", | ||
error, | ||
errors, | ||
}); | ||
|
||
/*************************************************************************************************** | ||
* @section Destructors | ||
**************************************************************************************************/ | ||
|
||
export const fold = <E, R>(patterns: { | ||
Leaf: (input: unknown, error: E) => R; | ||
Key: (key: string, kind: Kind, errors: FS.FreeSemigroup<DecodeError<E>>) => R; | ||
Index: ( | ||
index: number, | ||
kind: Kind, | ||
errors: FS.FreeSemigroup<DecodeError<E>>, | ||
) => R; | ||
Member: (index: number, errors: FS.FreeSemigroup<DecodeError<E>>) => R; | ||
Lazy: (id: string, errors: FS.FreeSemigroup<DecodeError<E>>) => R; | ||
Wrap: (error: E, errors: FS.FreeSemigroup<DecodeError<E>>) => R; | ||
}): ((e: DecodeError<E>) => R) => { | ||
const f = (e: DecodeError<E>): R => { | ||
switch (e.tag) { | ||
case "Leaf": | ||
return patterns.Leaf(e.actual, e.error); | ||
case "Key": | ||
return patterns.Key(e.key, e.kind, e.errors); | ||
case "Index": | ||
return patterns.Index(e.index, e.kind, e.errors); | ||
case "Member": | ||
return patterns.Member(e.index, e.errors); | ||
case "Lazy": | ||
return patterns.Lazy(e.id, e.errors); | ||
case "Wrap": | ||
return patterns.Wrap(e.error, e.errors); | ||
} | ||
}; | ||
return f; | ||
}; | ||
|
||
/*************************************************************************************************** | ||
* @section Module Getters | ||
**************************************************************************************************/ | ||
|
||
export const getSemigroup = <E = never>(): Semigroup< | ||
FS.FreeSemigroup<DecodeError<E>> | ||
> => FS.getSemigroup(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.