Last active
November 9, 2018 19:55
-
-
Save wernerdegroot/be1769d1ca7663cec0a1ba94ae400d04 to your computer and use it in GitHub Desktop.
Lens.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
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