Last active
February 11, 2018 00:34
-
-
Save sledorze/703af9b878efcf27b9e23036657d811e to your computer and use it in GitHub Desktop.
Sketch of 'ReadStatus' using fp-ts / io-ts
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
import * as t from 'io-ts' | |
import { Chain1 } from 'fp-ts/lib/Chain' | |
import { Foldable1 } from 'fp-ts/lib/Foldable' | |
import { Functor1 } from 'fp-ts/lib/Functor' | |
import { Monad1 } from 'fp-ts/lib/Monad' | |
import { Monoid } from 'fp-ts/lib/Monoid' | |
import { Plus1 } from 'fp-ts/lib/Plus' | |
import { Semigroup } from 'fp-ts/lib/Semigroup' | |
declare module 'fp-ts/lib/HKT' { | |
interface URI2HKT<A> { | |
ReadStatus: ReadStatus<A> | |
} | |
} | |
export const URI = 'ReadStatus' | |
export type URI = typeof URI | |
export class ReadWaiting<A> { | |
// prettier-ignore | |
readonly '_A': A | |
// prettier-ignore | |
readonly '_URI': URI | |
readonly _t: 'w' = 'w' | |
private constructor() {} | |
static value: ReadStatus<never> = new ReadWaiting() | |
map<B>(_f: (a: A) => B): ReadStatus<B> { | |
return ReadWaiting.value | |
} | |
chain<B>(_f: (a: A) => ReadStatus<B>): ReadStatus<B> { | |
return ReadWaiting.value | |
} | |
ap<B>(_fab: ReadStatus<(a: A) => B>): ReadStatus<B> { | |
return ReadWaiting.value | |
} | |
fold<B>(w: B, _n: B, _v: (a: A) => B): B { | |
return w | |
} | |
reduce<B>(b: B, _f: (b: B, a: A) => B): B { | |
return b | |
} | |
alt(b: ReadStatus<A>): ReadStatus<A> { | |
return b.fold(this as ReadStatus<A>, this as ReadStatus<A>, of) | |
} | |
} | |
export const readWaiting = ReadWaiting.value | |
export const isWaiting = <T>(s: ReadStatus<T>): s is ReadWaiting<T> => s._t === 'w' | |
export class ReadNothing<A> { | |
// prettier-ignore | |
readonly '_A': A | |
// prettier-ignore | |
readonly '_URI': URI | |
readonly _t: 'n' = 'n' | |
private constructor() {} | |
static value: ReadStatus<never> = new ReadNothing() | |
map<B>(_f: (a: A) => B): ReadStatus<B> { | |
return ReadNothing.value | |
} | |
chain<B>(_f: (a: A) => ReadStatus<B>): ReadStatus<B> { | |
return ReadNothing.value | |
} | |
ap<B>(_fab: ReadStatus<(a: A) => B>): ReadStatus<B> { | |
return ReadNothing.value | |
} | |
fold<B>(_w: B, n: B, _v: (a: A) => B): B { | |
return n | |
} | |
reduce<B>(b: B, _f: (b: B, a: A) => B): B { | |
return b | |
} | |
alt(b: ReadStatus<A>): ReadStatus<A> { | |
return b | |
} | |
} | |
export const readNothing = ReadNothing.value | |
export const hasNothing = <T>(s: ReadStatus<T>): s is ReadNothing<T> => s._t === 'n' | |
export class ReadValue<A> { | |
// prettier-ignore | |
readonly '_A': A | |
// prettier-ignore | |
readonly '_URI': URI | |
readonly _t: 'v' = 'v' | |
constructor(readonly v: A) {} | |
map<B>(f: (a: A) => B): ReadStatus<B> { | |
return new ReadValue(f(this.v)) | |
} | |
chain<B>(f: (a: A) => ReadStatus<B>): ReadStatus<B> { | |
return f(this.v) | |
} | |
ap<B>(fab: ReadStatus<(a: A) => B>): ReadStatus<B> { | |
return fab.map(f => f(this.v)) | |
} | |
fold<B>(_w: B, _n: B, v: (a: A) => B): B { | |
return v(this.v) | |
} | |
reduce<B>(b: B, f: (b: B, a: A) => B): B { | |
return f(b, this.v) | |
} | |
alt(_b: ReadStatus<A>): ReadStatus<A> { | |
return this | |
} | |
} | |
export const readValue = <T>(v: T): ReadStatus<T> => new ReadValue<T>(v) | |
export const hasValue = <T>(s: ReadStatus<T>): s is ReadValue<T> => s._t === 'v' | |
export type ReadStatus<T> = ReadWaiting<T> | ReadNothing<T> | ReadValue<T> | |
export const getMonoid = <A>(S: Semigroup<A>): Monoid<ReadStatus<A>> => { | |
return { | |
concat: (x, y) => x.fold(y, y, ax => y.fold(x, x, ay => of(S.concat(ax, ay)))), // TODO: Verify laws | |
empty: ReadNothing.value | |
} | |
} | |
const map = <A, B>(fa: ReadStatus<A>, f: (a: A) => B): ReadStatus<B> => { | |
return fa.map(f) | |
} | |
const chain = <A, B>(fa: ReadStatus<A>, f: (a: A) => ReadStatus<B>): ReadStatus<B> => { | |
return fa.chain(f) | |
} | |
const ap = <A, B>(fab: ReadStatus<(a: A) => B>, fa: ReadStatus<A>): ReadStatus<B> => { | |
return fa.ap(fab) | |
} | |
const of = <A>(a: A): ReadValue<A> => { | |
return new ReadValue(a) | |
} | |
const zero = <A>(): ReadStatus<A> => ReadNothing.value | |
const alt = <A>(fx: ReadStatus<A>, fy: ReadStatus<A>): ReadStatus<A> => { | |
return fx.alt(fy) | |
} | |
const reduce = <A, B>(fa: ReadStatus<A>, b: B, f: (b: B, a: A) => B): B => { | |
return fa.reduce(b, f) | |
} | |
export const readStatus: Monad1<URI> & Foldable1<URI> & Functor1<URI> & Chain1<URI> & Plus1<URI> = { | |
URI, | |
of, | |
map, | |
ap, | |
chain, | |
reduce, | |
zero, | |
alt | |
} | |
export type JSONReadStatus<A> = | |
| { readonly _t: 'w' } | |
| { readonly _t: 'n' } | |
| { readonly _t: 'v'; readonly v: A } | |
export function ReadStatus<A>(type: t.Type<t.mixed, A>): t.Type<t.mixed, ReadStatus<A>> { | |
const JSONReadStatus: t.Type<t.mixed, JSONReadStatus<A>> = t.taggedUnion('_t', [ | |
t.interface({ | |
_t: t.literal('w') | |
}), | |
t.interface({ | |
_t: t.literal('n') | |
}), | |
t.interface({ | |
_t: t.literal('v'), | |
v: type | |
}) | |
]) | |
return new t.Type( | |
`ReadStatus<${type.name}>`, | |
(v): v is ReadStatus<A> => | |
v instanceof ReadNothing || v instanceof ReadValue || v instanceof ReadWaiting, | |
(s, c) => | |
JSONReadStatus.validate(s, c).map(o => { | |
switch (o._t) { | |
case 'w': | |
return ReadWaiting.value | |
case 'n': | |
return ReadNothing.value | |
case 'v': | |
return new ReadValue(o.v) | |
} | |
}), | |
a => | |
a.fold<JSONReadStatus<A>>({ _t: 'w' as 'w' }, { _t: 'n' as 'n' }, v => ({ | |
_t: 'v' as 'v', | |
v | |
})) | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment