// @flow import type { Getter } from './Getter' import type { POptional } from './POptional' import type { Either } from './Either' import * as either from './Either' import * as getter from './Getter' /* A Lens is an optic used to zoom inside a Product, e.g. case class, Tuple, HList or even Map. Lenses have two type parameters generally called S and A: Lens[S, A] where S represents the Product and A an element inside of S. */ export interface PLens extends Getter { set(b: B, s: S): T } export type Lens = PLens; export function modify(lens: PLens, f: (a: A) => B, s: S): T { return lens.set(f(lens.get(s)), s) } /** join two PLens with the same target */ export function choice(lens1: PLens, lens2: PLens): PLens, Either, A, B> { return { get: getter.choice(lens1, lens2).get, set(b: B, s: Either): Either { return either.bimap(s1 => lens1.set(b, s1), s2 => lens2.set(b, s2), s) } } } export function asOptional(lens: PLens): POptional { return { getOrModify(s: S): Either { return either.right(lens.get(s)) }, set: lens.set } } export function composeLens(abcd: PLens, stab: PLens): PLens { return { get(s: S): C { return abcd.get(stab.get(s)) }, set(d: D, s: S): T { return modify(stab, a => abcd.set(d, a), s) } } }