Last active
February 27, 2018 22:38
-
-
Save josephjunker/8a7826a856426d13529208cdcfb08ce6 to your computer and use it in GitHub Desktop.
Laziness primitive for JS, flow-static-land compatible
This file contains hidden or 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
// Note that this file still needs testing | |
// @flow | |
export opaque type Deferred<A> = Thunk<A> | Pure<A>; | |
class Suspended<A> { | |
fn: () => A; | |
constructor(fn: () => A) { | |
this.fn = fn; | |
} | |
} | |
class Resolved<A> { | |
value: A; | |
constructor(value: A) { | |
this.value = value; | |
} | |
} | |
class Thunk<A> { | |
contents: Suspended<A> | Resolved<A>; | |
constructor(contents: Suspended<A>) { | |
this.contents = contents; | |
} | |
} | |
class Pure<A> { | |
value: A; | |
constructor(value: A) { | |
this.value = value; | |
} | |
} | |
export function defer<A>(fn: () => A) : Deferred<A> { | |
return new Thunk(new Suspended(fn)); | |
} | |
export function force<A>(d: Deferred<A>) : A { | |
if (d instanceof Pure) return d.value; | |
if (d.contents instanceof Resolved) return d.contents.value; | |
const result = d.contents.fn(); | |
d.contents = new Resolved(result); | |
return result; | |
} | |
export function pure<A>(a: A): Deferred<A> { | |
return new Pure(a); | |
} |
This file contains hidden or 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
// Note that this file still needs testing | |
// @flow | |
import { unsafeCoerce } from "flow-static-land/lib/unsafe"; | |
import { HKT } from "flow-static-land/lib/HKT"; | |
import type { Monad } from "flow-static-land/lib/Monad"; | |
class IsDeferred {} | |
export type Deferred<A> = HKT<IsDeferred, A>; | |
type DeferredI<A> = Thunk<A> | Pure<A>; | |
function inj<A>(deferred: DeferredI<A>) : Deferred<A> { | |
return unsafeCoerce(deferred); | |
} | |
function prj<A>(deferred: Deferred<A>) : DeferredI<A> { | |
return unsafeCoerce(deferred); | |
} | |
class Suspended<A> { | |
fn: () => A; | |
constructor(fn: () => A) { | |
this.fn = fn; | |
} | |
} | |
class Resolved<A> { | |
value: A; | |
constructor(value: A) { | |
this.value = value; | |
} | |
} | |
class Thunk<A> { | |
contents: Suspended<A> | Resolved<A>; | |
constructor(contents: Suspended<A>) { | |
this.contents = contents; | |
} | |
} | |
class Pure<A> { | |
value: A; | |
constructor(value: A) { | |
this.value = value; | |
} | |
} | |
export function defer<A>(fn: () => A) : Deferred<A> { | |
return inj(new Thunk(new Suspended(fn))); | |
} | |
export function force<A>(deferred: Deferred<A>) : A { | |
const d = prj(deferred); | |
if (d instanceof Pure) return d.value; | |
if (d.contents instanceof Resolved) return d.contents.value; | |
const result = d.contents.fn(); | |
d.contents = new Resolved(result); | |
return result; | |
} | |
export function map<A, B>(fn: A => B, deferred: Deferred<A>) : Deferred<B> { | |
return defer(() => fn(force(deferred))); | |
} | |
export function of<A>(a: A): Deferred<A> { | |
return inj(new Pure(a)); | |
} | |
export function ap<A, B>(deferredFn: Deferred<A => B>, deferred: Deferred<A>) : Deferred<B> { | |
return defer(() => force(deferredFn)(force(deferred))); | |
} | |
export function chain<A, B>(fn: A => Deferred<B>, deferred: Deferred<A>): Deferred<B> { | |
return defer(() => force(fn(force(deferred)))); | |
} | |
export const deferred = { | |
map, | |
of, | |
ap, | |
chain | |
}; | |
if (false) { | |
(deferred : Monad<IsDeferred>); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment