Skip to content

Instantly share code, notes, and snippets.

@wernerdegroot
Last active November 9, 2018 19:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wernerdegroot/be1769d1ca7663cec0a1ba94ae400d04 to your computer and use it in GitHub Desktop.
Save wernerdegroot/be1769d1ca7663cec0a1ba94ae400d04 to your computer and use it in GitHub Desktop.
Lens.ts
class Lens<Outer, Inner> {
static create<O>(): Lens<O, O> {
return new Lens(o => o, o => o, [])
}
constructor(public readonly read: (outer: Outer) => Inner, public readonly write: (inner: Inner, outer: Outer) => Outer, public readonly path: Array<string | number | Symbol>) { }
property<K extends keyof Inner>(k: K): Lens<Outer, Inner[K]> {
return new Lens(
(outer: Outer) => this.read(outer)[k],
(inner: Inner[K], outer: Outer) => this.write({...this.read(outer), [k]: inner }, outer),
[...this.path, k]
)
}
doRead(): ReadOperation<Outer, Inner> {
return new ReadOperation(this.read, this.path)
}
}
interface Operation<Outer, Inner> {
execute(getOuter: () => Outer): Inner
}
class ReadOperation<Outer, Inner> implements Operation<Outer, Inner> {
constructor(private readonly reader: (outer: Outer) => Inner, private readonly path: Array<string | number | Symbol>) {
}
execute(getOuter: () => Outer) {
const inner = this.reader(getOuter())
console.log(this.path, inner)
return inner
}
flatMap<NewInner>(fn: (inner: Inner) => Operation<Outer, NewInner>): FlatMappedOperation<Outer, Inner, NewInner> {
return new FlatMappedOperation(this, fn)
}
}
class FlatMappedOperation<Outer, Middle, Inner> implements Operation<Outer, Inner> {
constructor(private readonly readOperation: Operation<Outer, Middle>, private readonly fn: (middle: Middle) => Operation<Outer, Inner>) {
}
execute(getOuter: () => Outer) {
const middle = this.readOperation.execute(getOuter)
const inner = this.fn(middle).execute(getOuter)
return inner
}
}
const henk = {
a: 'a',
b: 2,
c: true
}
const lensA = Lens.create<typeof henk>().property('a')
const lensB = Lens.create<typeof henk>().property('b')
const lensC = Lens.create<typeof henk>().property('c')
const lens = lensA.doRead().flatMap(a => {
return lensB.doRead().flatMap(b => {
return lensC.doRead()
})
}).execute(() => henk)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment