import { Monoid , MonoidConstructor } from "./monoid" ; import { Applicative , ApplicativeDictionary } from "./applicative" ; import { foldable , Foldable } from "./foldable" ; import { Traversable } from "./traversable" ; import { Monad } from "./monad" ; import { Either } from "./either" ; import { id } from "./utils" ; export type MaybeMatch < T , K > = { nothing : ( ) => K ; just : ( t : T ) => K ; } ; export abstract class Maybe < A > implements Monad < A > , Foldable < A > { isMaybe : true ; abstract match < K > ( m ) ; of < B > ( v ) { return just ( v ) ; } static of < B > ( v ) { return just ( v ) ; } static is ( a ) { return typeof a === "object" && a . isMaybe === true ; } abstract chain < B > ( f ) ; flatten < B > ( ) { return ( this as any ) . match ( { nothing : ( ) => nothing , just : id } ) ; } abstract map < B > ( f ) ; abstract mapTo < B > ( b ) ; abstract ap < B > ( a ) ; lift < T1 , R > ( f , m ) ; lift < T1 , T2 , R > ( f , m1 , m2 ) ; lift < T1 , T2 , T3 , R > ( f , m1 , m2 , m3 ) ; lift ( ) { const f = arguments [ 0 ] ; for ( let i = 1 ; i < arguments . length ; ++ i ) { if ( isNothing ( arguments [ i ] ) ) { return nothing ; } } switch ( arguments . length - 1 ) { case 1 : return just ( f ( arguments [ 1 ] . val ) ) ; case 2 : return just ( f ( arguments [ 1 ] . val , arguments [ 2 ] . val ) ) ; case 3 : return just ( f ( arguments [ 1 ] . val , arguments [ 2 ] . val , arguments [ 3 ] . val ) ) ; } } abstract foldr < B > ( f , init ) ; abstract foldl < B > ( f , init ) ; shortFoldr : < B > ( f : ( a : A , b : B ) => Either < B , B > , acc : B ) => B ; shortFoldl : < B > ( f : ( acc : B , a : A ) => Either < B , B > , acc : B ) => B ; maximum : ( ) => number ; minimum : ( ) => number ; sum : ( ) => number ; abstract size ( ) ; abstract traverse < B > ( a , f ) ; sequence < A > ( a , m ) { return m . match ( { nothing : ( ) => a . of ( nothing ) , just : v => v . map ( just ) } ) ; } static multi : boolean = false ; multi : boolean = false ; } @ foldable class Nothing < A > extends Maybe < A > { constructor ( ) { super ( ) ; this . isMaybe = true ; } match < K > ( m ) { return m . nothing ( ) ; } chain < B > ( f ) { return nothing ; } map < B > ( f ) { return nothing ; } mapTo < B > ( b ) { return nothing ; } ap < B > ( a ) { return nothing ; } foldr < B > ( f , init ) { return init ; } foldl < B > ( f , init ) { return init ; } size ( ) { return 0 ; } traverse < B > ( a , f ) { return a . of ( nothing ) ; } } @ foldable class Just < A > extends Maybe < A > { val : A ; constructor ( val ) { super ( ) ; this . isMaybe = true ; this . val = val ; } match < K > ( m ) { return m . just ( this . val ) ; } chain < B > ( f ) { return f ( this . val ) ; } map < B > ( f ) { return new Just ( f ( this . val ) ) ; } mapTo < B > ( b ) { return new Just < B > ( b ) ; } ap < B > ( m ) { return m . match ( { nothing : ( ) => nothing , just : f => new Just ( f ( this . val ) ) } ) ; } foldr < B > ( f , init ) { return f ( this . val , init ) ; } foldl < B > ( f , init ) { return f ( init , this . val ) ; } size ( ) { return 1 ; } traverse < B > ( a , f ) { return f ( this . val ) . map ( just ) ; } } export function just < V > ( v ) { return new Just ( v ) ; } export const nothing = new Nothing ( ) ; export function isNothing ( m ) { return m === nothing ; } export function isJust ( m ) { return m !== nothing ; } export function fromMaybe < A > ( a , m ) { return m === nothing ? a : ( < Just < A > > m ) . val ; } export function maybe < A , B > ( b , f , m ) { return m === nothing ? b : f ( ( < Just < A > > m ) . val ) ; }