import { Parameter , unknown } from "../.." ; import { test } from "../../tests/harness" ; import { GenericMonad , Matchable , Monad } from "./adt" ; import { Maybe , None , maybe } from "./maybe" ; const GenericEither = < G extends GenericMonad < any > > ( { left , right , match } ) : Monad < G > => { const map = < A , B > ( f ) : ( < F extends GenericMonad < G , A > > ( monadic : F ) => GenericMonad < F , B > ) => match ( { left : left as any , right : ( value ) => right ( f ( value ) ) } ) ; const of = right ; const chain = < T , U extends GenericMonad < G > > ( f ) => match ( { left : left as any , right : f } ) ; return { map , of , chain } ; } ; type Either < T , U > = Left < T > | Right < U > ; interface Left < T > { left : T ; } interface Right < T > { right : T ; } declare module "typeprops" { interface TypeProps < T , Params > { "examples/pattern-matching/either#either" : { infer : ( T extends Left < infer T > ? [ T , never ] : never ) | ( T extends Right < infer U > ? [ never , U ] : never ) ; construct : Either < Params [ 0 ] , Params [ 1 ] > ; } ; } } declare module "./adt" { interface MonadProps < T , Params > { "examples/pattern-matching/either#either" : { infer : T extends Either < any , infer U > ? [ U ] : never ; construct : Either < Parameter < T > , Params [ 0 ] > ; } ; } } { const left = < T > ( left ) => ( { left } as Either < T , never > ) ; const right = < T > ( right ) => ( { right } as Either < never , T > ) ; const match = < L1 , R1 , L2 , R2 > ( { left , right } ) => ( either ) : L2 | R2 => "left" in either ? left ( either . left ) : right ( either . right ) ; const { of , map , chain } = GenericEither < Left < unknown > | Right < never > > ( { left , right , match } ) ; test ( "examples/pattern-matching/either1" , test => { test . plan ( 6 ) ; test . deepEqual < Either < unknown , number > > ( of ( 42 ) ) ( map ( ( x ) => x * 2 ) ( of ( 21 ) ) ) ; test . deepEqual < Either < string , number > > ( left ( "error" ) ) ( map ( ( x ) => x * 2 ) ( left ( "error" ) ) ) ; test . deepEqual < Either < unknown , number > > ( left ( "error" ) ) ( chain ( ( x ) => ( x > 40 ? left ( "error" ) : of ( x * 2 ) ) ) ( of ( 42 ) ) ) ; test . deepEqual < Either < unknown , number > > ( of ( 64 ) ) ( chain ( ( x ) => ( x > 40 ? left ( "error" ) : of ( x * 2 ) ) ) ( of ( 32 ) ) ) ; test . deepEqual < Either < unknown , Either < string , never > > > ( of ( left ( "error" ) ) ) ( map ( ( ) => left ( "error" ) ) ( of ( 42 ) ) ) ; test . deepEqual < Either < unknown , Either < unknown , number > > > ( of ( of ( 84 ) ) ) ( map ( ( x ) => of ( x * 2 ) ) ( of ( 42 ) ) ) ; } ) ; } { const { none , just , match } = maybe ; const { of , map , chain } = GenericEither < Maybe < never > > ( { left : none , right : just , match : < T , B > ( { left , right } ) => match ( { none : left , just : right } ) } ) ; test ( "examples/pattern-matching/either2" , test => { test . plan ( 6 ) ; test . deepEqual < Maybe < number > > ( of ( 42 ) ) ( map ( ( x ) => x * 2 ) ( of ( 21 ) ) ) ; test . deepEqual < Maybe < number > > ( none ) ( map ( ( x ) => x * 2 ) ( none ) ) ; test . deepEqual < Maybe < number > > ( none ) ( chain ( ( x ) => ( x > 40 ? none : of ( x * 2 ) ) ) ( of ( 42 ) ) ) ; test . deepEqual < Maybe < number > > ( of ( 64 ) ) ( chain ( ( x ) => ( x > 40 ? none : of ( x * 2 ) ) ) ( of ( 32 ) ) ) ; test . deepEqual < Maybe < None > > ( of ( none ) ) ( map ( ( ) => none ) ( of ( 42 ) ) ) ; test . deepEqual < Maybe < Maybe < number > > > ( of ( of ( 84 ) ) ) ( map ( ( x ) => of ( x * 2 ) ) ( of ( 42 ) ) ) ; } ) ; }