import { curry } from '../curry'; import { prop } from '../prop'; import { path } from '../path'; import { Optional, ValueOf } from '../common'; import { assoc } from '../assoc'; import { assocPath } from '../assocPath'; interface ILens { get: (value: T) => ValueOf; set: (value: V) => void; } type ILensFn = { (get: ILens['get'], set: ILens['set']): ILens; (get: ILens['get']): (set: ILens['set']) => ILens; } const lens: ILensFn = curry((get, set) => ({ get, set })); type IView = { (lens: ILens): ILens['get']; (lens: ILens, object: L): R; } export const view: IView = curry((lens, obj) => lens.get(obj)); type ISet = { (lens: ILens): (value: V) => (object: O) => T; (lens: ILens, value: V): (object: O) => T; (lens: ILens, value: V, object: O): T; } export const set: ISet = curry((lens, value, object) => lens.set(value)(object)); export const over = curry((lens, fn, obj) => set(lens)(fn(view(lens)(obj)))(obj)); export const lensProp = (key: string) => lens(prop(key), assoc(key)); export const lensPath = (key: string[]) => lens(path(key))(assocPath(key));