Skip to content

Instantly share code, notes, and snippets.

@sledorze
Last active February 11, 2018 00:34
Show Gist options
  • Save sledorze/703af9b878efcf27b9e23036657d811e to your computer and use it in GitHub Desktop.
Save sledorze/703af9b878efcf27b9e23036657d811e to your computer and use it in GitHub Desktop.
Sketch of 'ReadStatus' using fp-ts / io-ts
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