import { Option } from './../utils' ; export interface Optic < TSource , T , U > { get ( s ) : T ; set ( v , s ) : TSource ; modify ( updateFn , s ) : TSource ; } function createModify < TSource , T , U > ( getter , setter ) { return function modify ( updateFn , s ) { return setter ( updateFn ( getter ( s ) ) , s ) ; } ; } export namespace Optic { export function optic < TSource , T , U > ( getter , setter ) { return { get : getter , set : setter , modify : createModify ( getter , setter ) } ; } } /**
 * The lens interface.
 *
 * Lens is a kind of functional reference – an abstraction that allows
 * you to operate on part(s) of a value in a purely-functional setting.
 *
 * Read more here: https://en.wikibooks.org/wiki/Haskell/Lenses_and_functional_references
 */ export interface Lens < TSource , T > extends Optic < TSource , T , T > { compose < U > ( next ) : Lens < TSource , U > ; compose < U > ( next ) : Prism < TSource , U > ; } export interface Prism < TSource , T > extends Optic < TSource , Option < T > , T > { compose < U > ( next ) : Prism < TSource , U > ; compose < U > ( next ) : Lens < TSource , U > ; compose < U > ( next ) : Prism < TSource , U > ; } export namespace Prism { export function create < TSource , T > ( getter , setter ) { return { get : getter , set : setter , modify : createModify ( getter , setter ) , compose < U > ( next ) { return create ( ( s ) => { const x = getter ( s ) ; return x !== undefined ? next . get ( x ) : undefined ; } , ( v , s ) => { const x = getter ( s ) ; return x !== undefined ? setter ( next . set ( v , x ) , s ) : s ; } ) ; } } ; } } export namespace Lens { export template O template P param getter param setter returns export function create < TSource , T > ( getter , setter ) { return { get : getter , set : setter , modify : createModify ( getter , setter ) , compose < U > ( next ) { return create ( ( s ) => next . get ( getter ( s ) ) , ( v , s ) => setter ( next . set ( v , getter ( s ) ) , s ) ) ; } } ; } static template S template A export function compose < T , U > ( l ) ; export function compose < T1 , T2 , U > ( l1 , l2 ) ; export function compose < T1 , T2 , T3 , U > ( l1 , l2 , l3 ) ; export function compose < T1 , T2 , T3 , T4 , U > ( l1 , l2 , l3 , l4 ) ; export function compose < T1 , T2 , T3 , T4 , T5 , U > ( l1 , l2 , l3 , l4 , l5 ) ; export function compose < T , U > ( ... lenses ) ; export function compose < T , U > ( ... lenses ) { if ( lenses . length === 0 ) { throw new TypeError ( 'Can not compose zero lenses. You probably want `Lens.identity`.' ) ; } else if ( lenses . length === 1 ) { return lenses [ 0 ] ; } else { let r = lenses [ 0 ] ; lenses . slice ( 1 ) . forEach ( l => { r = r . compose ( l ) ; } ) ; return r as Lens < T , U > ; } } const _identity = create < any , any > ( x => x , ( x , _ ) => x ) ; /**
     * The identity lens – a lens that reads and writes the object itself.
     */ export function identity < T > ( ) { return _identity as Lens < T , T > ; } const _nothing = Prism . create ( _ => undefined , ( _ , o ) => o ) ; /**
     * A lens that always returns `undefined` on `get` and does no change on `set`.
     */ export function nothing < TSource , T > ( ) { return _nothing as Prism < TSource , T > ; } }