import { Functor } from "./functor" ; import { AbstractMonad , Monad , monad } from "./monad" ; export type FreerMatch < F , A , K > = { pure : ( a : A ) => K ; bind : ( u : F , k : ( a : any ) => Freer < F , A > ) => K ; } ; export abstract class Freer < F , A > extends AbstractMonad < A > { static of < B > ( b ) { return new Pure ( b ) ; } of < B > ( b ) { return new Pure ( b ) ; } abstract match < K > ( m ) ; abstract map < B > ( f ) ; multi : false ; static multi = false ; abstract chain < B > ( f ) ; } @ monad export class Pure < F , A > extends Freer < F , A > { constructor ( private a ) { super ( ) ; } match < K > ( m ) { return m . pure ( this . a ) ; } map < B > ( f ) { return new Pure ( f ( this . a ) ) ; } chain < B > ( f ) { return f ( this . a ) ; } } function pure < F , A > ( a ) { return new Pure ( a ) ; } @ monad export class Bind < F , A > extends Freer < F , A > { constructor ( public val , public f ) { super ( ) ; } match < K > ( m ) { return m . bind ( this . val , this . f ) ; } map < B > ( f ) { return new Bind ( this . val , ( a ) => this . f ( a ) . map ( f ) ) ; } chain < B > ( f ) { return new Bind ( this . val , ( a ) => this . f ( a ) . chain ( f ) ) ; } } export function liftF < F , A > ( fa ) { return new Bind ( fa , pure ) ; }