import { Either , Left , Right } from './Either' ; import { ApKind , ofAp } from './pointfree/ap' ; import { ofSymbol } from './pointfree/do' ; import { ReplaceFirst , Type , URIS } from './pointfree/hkt' ; export type MaybePatterns < T , U > = { Just : ( value : T ) => U ; Nothing : ( ) => U ; } | { _ : ( ) => U ; } ; interface AlwaysJust { kind : '$$MaybeAlwaysJust' ; } export const MAYBE_URI = 'Maybe' ; export type MAYBE_URI = typeof MAYBE_URI ; declare module './pointfree/hkt' { export interface URI2HKT < Types extends any [ ] > { [ MAYBE_URI ] : Maybe < Types [ 0 ] > ; } } type ExtractMaybe < T , TDefault > = T extends never ? TDefault : T | TDefault ; export interface Maybe < T > { readonly _URI : MAYBE_URI ; readonly _A : [ T ] ; [ ofSymbol ] : MaybeTypeRef [ 'of' ] ; [ Symbol . iterator ] : ( ) => Iterator < Type < MAYBE_URI , [ T ] > , T , any > ; /** Returns true if `this` is `Just`, otherwise it returns false */ isJust ( ) : this is AlwaysJust ; /** Returns true if `this` is `Nothing`, otherwise it returns false */ isNothing ( ) : this is Nothing ; inspect ( ) : string ; toString ( ) : string ; toJSON ( ) : T ; /** Compares the values inside `this` and the argument, returns true if both are Nothing or if the values are equal */ equals ( other ) : boolean ; /** Transforms the value inside `this` with a given function. Returns `Nothing` if `this` is `Nothing` */ map < U > ( f ) : Maybe < U > ; /** Maps `this` with a `Maybe` function */ ap < U > ( maybeF ) : Maybe < U > ; /** Returns the first `Just` between `this` and another `Maybe` or `Nothing` if both `this` and the argument are `Nothing` */ alt ( other ) : Maybe < T > ; /** Transforms `this` with a function that returns a `Maybe`. Useful for chaining many computations that may result in a missing value */ chain < U > ( f ) : Maybe < U > ; /** Transforms `this` with a function that returns a nullable value. Equivalent to `m.chain(x => Maybe.fromNullable(f(x)))` */ chainNullable < U > ( f ) : Maybe < U > ; /** Flattens nested Maybes. `m.join()` is equivalent to `m.chain(x => x)` */ join < U > ( this ) : Maybe < U > ; /** Takes a reducer and an initial value and returns the initial value if `this` is `Nothing` or the result of applying the function to the initial value and the value inside `this` */ reduce < U > ( reducer , initialValue ) : U ; /** Returns `this` if it's `Nothing`, otherwise it returns the result of applying the function argument to `this` and wrapping it in a `Just` */ extend < U > ( f ) : Maybe < U > ; /** Returns the value inside `this` or throws an error if `this` is `Nothing` */ unsafeCoerce ( ) : T ; /** Structural pattern matching for `Maybe` in the form of a function */ caseOf < U > ( patterns ) : U ; /** Returns the default value if `this` is `Nothing`, otherwise it return the value inside `this` */ orDefault ( defaultValue ) : T ; /** Lazy version of `orDefault`. Takes a function that returns the default value, that function will be called only if `this` is `Nothing` */ orDefaultLazy ( getDefaultValue ) : T ; /** Returns empty list if the `Maybe` is `Nothing` or a list where the only element is the value of `Just` */ toList ( ) : T [ ] ; /** Maps over `this` and returns the resulting value or returns the default value if `this` is `Nothing` */ mapOrDefault < U > ( f , defaultValue ) : U ; /** Returns the value inside `this` or undefined if `this` is `Nothing`. Use `extractNullable` if you need a null returned instead */ extract ( ) : this extends AlwaysJust ? T : ExtractMaybe < T , undefined > ; /** Returns the value inside `this` or null if `this` is `Nothing`. Use `extract` if you need an undefined returned instead */ extractNullable ( ) : this extends AlwaysJust ? T : ExtractMaybe < T , null > ; /** Constructs a `Right` from a `Just` or a `Left` with a provided left value if `this` is `Nothing` */ toEither < L > ( left ) : Either < L , T > ; /** Runs an effect if `this` is `Just`, returns `this` to make chaining other methods possible */ ifJust ( effect ) : this ; /** Runs an effect if `this` is `Nothing`, returns `this` to make chaining other methods possible */ ifNothing ( effect ) : this ; /** Takes a predicate function and returns `this` if the predicate returns true or Nothing if it returns false */ filter ( pred ) : Maybe < T > ; traverse < URI extends URIS , AP extends ApKind < any , any > = ApKind < URI , any > > ( of , f ) : Type < URI , ReplaceFirst < AP [ '_A' ] , Maybe < AP [ '_A' ] [ 0 ] > > > ; sequence < Ap extends ApKind < any , any > > ( this , of ) : Type < Ap [ '_URI' ] , ReplaceFirst < Ap [ '_A' ] , Maybe < Ap [ '_A' ] [ 0 ] > > > ; 'fantasy-land/traverse' : this [ 'traverse' ] ; 'fantasy-land/sequence' : this [ 'sequence' ] ; 'fantasy-land/equals' ( other ) : boolean ; 'fantasy-land/map' < U > ( f ) : Maybe < U > ; 'fantasy-land/ap' < U > ( maybeF ) : Maybe < U > ; 'fantasy-land/alt' ( other ) : Maybe < T > ; 'fantasy-land/chain' < U > ( f ) : Maybe < U > ; 'fantasy-land/reduce' < U > ( reducer , initialValue ) : U ; 'fantasy-land/extend' < U > ( f ) : Maybe < U > ; 'fantasy-land/filter' ( pred ) : Maybe < T > ; } interface MaybeTypeRef { /** Takes a value and wraps it in a `Just` */ of < T > ( value ) : Maybe < T > ; /** Returns `Nothing` */ empty ( ) : Nothing ; /** Returns `Nothing` */ zero ( ) : Nothing ; /** Takes a value and returns `Nothing` if the value is null or undefined, otherwise a `Just` is returned */ fromNullable < T > ( value ) : Maybe < T > ; /** Takes a value and returns Nothing if the value is falsy, otherwise a Just is returned */ fromFalsy < T > ( value ) : Maybe < T > ; /** Takes a predicate and a value, passes the value to the predicate and returns a Just if it returns true, otherwise a Nothing is returned */ fromPredicate < T > ( pred ) : ( value : T ) => Maybe < T > ; fromPredicate < T > ( pred , value ) : Maybe < T > ; /** Returns only the `Just` values in a list */ catMaybes < T > ( list ) : T [ ] ; /** Maps over a list of values and returns a list of all resulting `Just` values */ mapMaybe < T , U > ( f ) : ( list : T [ ] ) => U [ ] ; mapMaybe < T , U > ( f , list ) : U [ ] ; /** Calls a function that may throw and wraps the result in a `Just` if successful or `Nothing` if an error is caught */ encase < T > ( thunk ) : Maybe < T > ; isMaybe < T > ( x ) : x is Maybe < T > ; 'fantasy-land/of' < T > ( value ) : Maybe < T > ; 'fantasy-land/empty' ( ) : Nothing ; 'fantasy-land/zero' ( ) : Nothing ; } export const Maybe = { of < T > ( value ) { return just ( value ) ; } , empty ( ) { return nothing ; } , zero ( ) { return nothing ; } , fromNullable < T > ( value ) { return value == null ? nothing : just ( value ) ; } , fromFalsy < T > ( value ) { return value ? just ( value ) : nothing ; } , fromPredicate < T > ( pred , value ? ) { switch ( arguments . length ) { case 1 : return ( value ) => Maybe . fromPredicate ( pred , value ) ; default : return pred ( value ! ) ? just ( value ! ) : nothing ; } } , mapMaybe < T , U > ( f , list ? ) { switch ( arguments . length ) { case 1 : return ( list ) => Maybe . mapMaybe ( f , list ) ; default : return Maybe . catMaybes ( list ! . map ( f ) ) ; } } , catMaybes < T > ( list ) { let res = [ ] ; for ( const e of list ) { if ( e . isJust ( ) ) { res . push ( e . extract ( ) ) ; } } return res ; } , encase < T > ( thunk ) { try { return just ( thunk ( ) ) ; } catch { return nothing ; } } , isMaybe < T > ( x ) { return x instanceof Just || x instanceof Nothing ; } , 'fantasy-land/of' < T > ( value ) { return this . of ( value ) ; } , 'fantasy-land/empty' ( ) { return this . empty ( ) ; } , 'fantasy-land/zero' ( ) { return this . zero ( ) ; } } ; class Just < T > implements Maybe < T > { constructor ( private __value ) { } * [ Symbol . iterator ] ( ) { return ( yield this ) as T ; } [ ofSymbol ] = Maybe . of ; readonly _URI ! : MAYBE_URI ; readonly _A ! : [ T ] ; isJust ( ) { return true ; } isNothing ( ) { return false ; } inspect ( ) { return `Just(${ JSON . stringify ( this . __value ) })` ; } toString ( ) { return this . inspect ( ) ; } toJSON ( ) { return this . __value ; } equals ( other ) { return this . extract ( ) === other . extract ( ) ; } map < U > ( f ) { return just ( f ( this . __value ) ) ; } traverse < URI extends URIS , AP extends ApKind < any , any > = ApKind < URI , any > > ( _of , f ) { const result = f ( this . __value ) ; return result . map ( just ) ; } 'fantasy-land/traverse' < URI extends URIS , AP extends ApKind < any , any > = ApKind < URI , any > > ( of , f ) { return this . traverse ( of , f ) ; } 'fantasy-land/sequence' < Ap extends ApKind < any , any > > ( this , of ) { return this . sequence ( of ) ; } sequence < Ap extends ApKind < any , any > > ( this , _of ) { return ( this as any ) . __value . map ( just ) ; } ap < U > ( maybeF ) { return maybeF . isJust ( ) ? this . map ( maybeF . extract ( ) ) : nothing ; } alt ( _ ) { return this ; } chain < U > ( f ) { return f ( this . __value ) ; } chainNullable < U > ( f ) { return Maybe . fromNullable ( f ( this . __value ) ) ; } join < U > ( this ) { return this . __value ; } reduce < U > ( reducer , initialValue ) { return reducer ( initialValue , this . __value ) ; } extend < U > ( f ) { return just ( f ( this ) ) ; } unsafeCoerce ( ) { return this . __value ; } caseOf < U > ( patterns ) { return '_' in patterns ? patterns . _ ( ) : patterns . Just ( this . __value ) ; } orDefault ( _ ) { return this . __value ; } orDefaultLazy ( _ ) { return this . __value ; } toList ( ) { return [ this . __value ] ; } mapOrDefault < U > ( f , _ ) { return f ( this . __value ) ; } extract ( ) { return this . __value as this extends AlwaysJust ? T : ExtractMaybe < T , undefined > ; } extractNullable ( ) { return this . __value as this extends AlwaysJust ? T : ExtractMaybe < T , null > ; } toEither < L > ( _ ) { return Right ( this . __value ) ; } ifJust ( effect ) { return effect ( this . __value ) , this ; } ifNothing ( _ ) { return this ; } filter ( pred ) { return pred ( this . __value ) ? just ( this . __value ) : nothing ; } 'fantasy-land/equals' ( other ) { return this . equals ( other ) ; } 'fantasy-land/map' < U > ( f ) { return this . map ( f ) ; } 'fantasy-land/ap' < U > ( maybeF ) { return this . ap ( maybeF ) ; } 'fantasy-land/alt' ( other ) { return this . alt ( other ) ; } 'fantasy-land/chain' < U > ( f ) { return this . chain ( f ) ; } 'fantasy-land/reduce' < U > ( reducer , initialValue ) { return this . reduce ( reducer , initialValue ) ; } 'fantasy-land/extend' < U > ( f ) { return this . extend ( f ) ; } 'fantasy-land/filter' ( pred ) { return this . filter ( pred ) ; } } Just . prototype . constructor = Maybe as any ; class Nothing implements Maybe < never > { * [ Symbol . iterator ] ( ) { return ( yield this ) as never ; } [ ofSymbol ] = Maybe . of ; private __value ! : never ; readonly _URI ! : MAYBE_URI ; readonly _A ! : [ never ] ; isJust ( ) { return false ; } isNothing ( ) { return true ; } inspect ( ) { return 'Nothing' ; } toString ( ) { return this . inspect ( ) ; } toJSON ( ) { return this . __value ; } equals < T > ( other ) { return this . extract ( ) === other . extract ( ) ; } map < U > ( _ ) { return nothing ; } traverse < URI extends URIS , AP extends ApKind < any , any > = ApKind < URI , any > > ( of , _f ) { return of ( this ) as any ; } 'fantasy-land/traverse' < URI extends URIS , AP extends ApKind < any , any > = ApKind < URI , any > > ( of , f ) { return this . traverse ( of , f ) ; } 'fantasy-land/sequence' < Ap extends ApKind < any , any > > ( this , of ) { return this . sequence ( of ) ; } sequence < Ap extends ApKind < any , any > > ( this , of ) { return of ( this ) as any ; } ap < U > ( _ ) { return nothing ; } alt < T > ( other ) { return other ; } chain < U > ( _ ) { return nothing ; } chainNullable < U > ( _ ) { return nothing ; } join < U > ( this ) { return nothing ; } reduce < U > ( _ , initialValue ) { return initialValue ; } extend < U > ( _ ) { return nothing ; } unsafeCoerce < T > ( ) { throw new Error ( 'Maybe#unsafeCoerce was ran on a Nothing' ) ; } caseOf < U > ( patterns ) { return '_' in patterns ? patterns . _ ( ) : patterns . Nothing ( ) ; } orDefault < T > ( defaultValue ) { return defaultValue ; } orDefaultLazy < T > ( getDefaultValue ) { return getDefaultValue ( ) ; } toList < T > ( ) { return [ ] ; } mapOrDefault < U > ( _ , defaultValue ) { return defaultValue ; } extract ( ) { return undefined as this extends AlwaysJust ? never : ExtractMaybe < never , undefined > ; } extractNullable ( ) { return null as this extends AlwaysJust ? never : ExtractMaybe < never , null > ; } toEither < L , T > ( left ) { return Left ( left ) ; } ifJust ( _ ) { return this ; } ifNothing ( effect ) { return effect ( ) , this ; } filter ( _ ) { return nothing ; } 'fantasy-land/equals' ( other ) { return this . equals ( other ) ; } 'fantasy-land/map' < U > ( f ) { return this . map ( f ) ; } 'fantasy-land/ap' < U > ( maybeF ) { return this . ap ( maybeF ) ; } 'fantasy-land/alt' ( other ) { return this . alt ( other ) ; } 'fantasy-land/chain' < U > ( f ) { return this . chain ( f ) ; } 'fantasy-land/reduce' < U > ( reducer , initialValue ) { return this . reduce ( reducer , initialValue ) ; } 'fantasy-land/extend' < U > ( f ) { return this . extend ( f ) ; } 'fantasy-land/filter' ( pred ) { return this . filter ( pred ) ; } } Nothing . prototype . constructor = Maybe as any ; /** Constructs a Just. Represents an optional value that exists */ const just = < T > ( value ) : Maybe < T > => new Just ( value ) ; /** Represents a missing value, you can think of it as a smart 'null' */ const nothing = new Nothing ( ) ; export { just as Just , nothing as Nothing } ;