Skip to content

Instantly share code, notes, and snippets.

@Magellol
Created February 26, 2020 21:39
Show Gist options
  • Save Magellol/696bfbc4ec2979081530022f1895ca3a to your computer and use it in GitHub Desktop.
Save Magellol/696bfbc4ec2979081530022f1895ca3a to your computer and use it in GitHub Desktop.
Quick and dirty approach to lenses
type Lens<O, V> = {
get: (o: O) => V
set: (value: V) => (o: O) => O,
update: (fn: (current: V) => V) => (o: O) => O
}
type Homework = {done: number};
type Person = {
age: number;
homework: Homework
}
function compose<O, A, B>(lens1: Lens<O, A>, lens2: Lens<A, B>): Lens<O, B> {
return {
get(o) {
return lens2.get(lens1.get(o))
},
set(value) {
return o => {
const a = lens2.set(value)(lens1.get(o));
return lens1.set(a)(o);
}
},
update(fn) {
return o => {
const b = fn(this.get(o));
return this.set(b)(o);
}
}
}
}
function createLens<O>() {
return <K extends keyof O>(key: K): Lens<O, O[K]> => ({
get(o) {
return o[key]
},
set(newValue) {
return (o) => Object.assign({}, o, { [key]: newValue })
},
update(fn) {
return o => this.set(
fn(this.get(o))
)(o)
},
})
}
const person1: Person = { age: 27, homework: { done: 0 } };
const doneLens = compose(createLens<Person>()('homework'), createLens<Homework>()('done'))
doneLens.set(2)(person1); // {age: 27, homework: {done: 2}}
doneLens.update(count => count+1)(person1); // {age: 27, homework: {done: 1}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment