Skip to content

Latest commit

 

History

History
1516 lines (1138 loc) · 51.8 KB

api.md

File metadata and controls

1516 lines (1138 loc) · 51.8 KB

Monadic JS Documentation

Modules:

Click a module name below to see its documentation

MonadicJS

Written By: Joel Dentici

Written On: 6/20/2017

This library provides implementations of common monads in JavaScript.

Utility functions for working with monads abstractly are also provided, as well as a generator-based do-notation utility.

MonadicJS.ArrayExtensions

Written By: Joel Dentici

Written On: 7/19/2017

Makes Array compatible with this library.

WARNING: This modifies the Array prototype so you should always unload it when done. You may still mess other code up if you use these extensions in an asynchronous section of code.

MonadicJS.Async

Written By: Joel Dentici

Written On: 6/25/2017

The Async monad represents computations that run in an asynchronous context.

Unlike Promises, an Async computation is lazily evaluated, so it won't be executed immediately. Asyncs can be turned into Promises by calling "run" on them and Promises can be turned into Asyncs by applying Async.fromPromise to them

all :: ...Async c e a → Async c e [a]

Returns an Async computation whose result combines all the results from the provided Asyncs.

If any of the Asyncs fail, then the resulting Async will have its error.

This can be called with an array or rest args.

There must be at least one computation provided, regardless of how this is called.

await :: Promise a e → Async (Promise a e) e a

This basically just maps Promises into Asyncs.

create :: ((a → ()) → (e → ()) → c) → Async c e a

Creates an Async computation. Takes a function that accepts two functions, one for a successful computation an one for a failed computation. This function is not executed until the Async is ran.

fail :: e → Async e e ()

Returns an Async computation that failed for the specified reason.

first :: ...Async c e a → Async c e a

Returns an Async computation whose result is the result of the first provided computation to finish.

fork :: (Async c b a, (a → d), (b → e)) → c

Runs the asynchronous computation. Its result will be passed to succ or fail as appropriate.

fromEither :: Either e a → Async () e a

Creates an Async computation whose result or failure is the value in the specified Either.

fromMaybe :: Maybe a → Async () NonExistenceError a

Creates an Async computation whose result is the value in the Maybe. If the Maybe is Nothing, then the Async computation will result in a NonExistenceError.

fromPromise :: Promise a e → Async (Promise a e) e a

Alias of await

of :: a → Async a () a

Alias for unit. Provided for fantasy-land compliance.

parallel :: WebWorker → ((a_0..a_n) → b) → (a_0..a_n) → Async () Error b

Allows running functions in a fully parallel context.

Functions cannot be curried! If you try to use a curried function with this, the result will be a CurryingError. If you pass in a function that has already been curried, you will get a ReferenceError on its curried arguments. This is because the function is serialized to source and passed to the worker for execution. Serializing a curried function does not carry its environment, so it will have free variables in its body.

Applying parallel to a WebWorker implementation returns a function that can be used to wrap functions to run on another thread/process and return their results in an Async.

Note that you can achieve concurrency with CPU-bound computations by just using Async computations -- All you need to do is break them up into chains where you return results with Async.of or even just by chaining map from an initial Async.of() and turn iteration into recursion (you can also write most loops as higher order functions but that is inelegant). This works, but it isn't truly parallel as it doesn't utilize multiple CPU cores. It is essentially just time-sharing of coroutines (which can be faster than threads or processes for simple tasks).

Using this will give you truly parallel computation.

run :: Async c e a → ()

Runs the asynchronous computation, discarding the result.

Scheduler a b c :: (a → b) → c

A function that can be applied to a thunk to possibly schedule the thunk to run at a later time.

Different schedulers return different results. The immediate scheduler x => x() returns the result of the thunk (b = c).

setScheduler :: Scheduler a b c → Scheduler a b d

Sets a new scheduler to use for all Async computations. Returns the old scheduler.

sleep :: int → Async int () ()

Creates an Async computation that sleeps for the specified timespan in milliseconds and returns no result.

throwE :: e → Async () e ()

Alias of fail

toPromise :: Async c e a → Promise a e

Forks the computation and returns a promise for its result.

try :: Async c e a → Async c e a

This method literally doesn't do anything. It is just here to make catching look more imperative by surrounding it with try.

unit :: a → Async a () a

Puts a value into the context of an Async computation.

wrap :: ((...any, e → a → ()) → c) → ...any → Async c e a

Wraps a callback taking async function so it becomes a function that returns Async computations.

wrapPromise :: (...any → Promise a e) → ...any → Async (Promise a e) e a

Wraps a promise returning async function so it becomes a function that returns Async computations.

MonadicJS.Async.AsyncComputation

Written By: Joel Dentici

Written On: 6/25/2017

Holds a thunked computation.

alt :: Async c e a → Async c e b → Async c e (a | b)

Alternative sequencing. The computation on the left is ran and if it is successful, its result is used. If it fails, then the computation on the right is ran and its result is used.

ap :: Async c e a → Async c e (a → b) → Async c e b

Flipped arguments for app. This is for fantasy-land, but probably isn't very useful as it breaks chaining.

app :: Async c e (a → b) → Async c e a → Async c e b

Applicative application. Applies the function result of this Async computation to the result of the specified Async computation. If used with an n-ary curried function, then app can be chained n times to fully apply it.

This is written such that chained applications will run the computations concurrently.

bind :: Async c e a → (a → Async c e b) → Async c e b

Alias for chain.

catch :: Async c e a → (e → Async c e2 b) → Async c e2 b

Alias for chainFail.

chain :: Async c e a → (a → Async c e2 b) → Async c e2 b

Monadic binding of Async computations. The computations run sequentially. Failed computations do not get piped through.

chainFail :: Async c e a → (e → Async c e2 b) → Async c e2 b

Same as chain/bind but the function is applied when this computation fails.

chainIt :: ((b → ()), (e → ()), (a → Async () e a)) → (a → ())

Performs the monadic chaining while catching any errors that occur.

doCase :: Async c e a → (((a → (), e → ()) → c) → b) → b

Applies the function to the thunked computation.

fork :: Async c e a → (a → (), e → ()) → ()

Runs the Async computation. The success or fail function is applied to its result, depending on whether it is successful or not.

later :: (a → b) → a → ()

Wraps the application to the specified function in an application of the scheduling function.

map :: Async c e a → (a → b) → Async c e b

Applies the function to the result of this computation.

mapCatch :: Async c e a → (e → e2) → Async c e2 a

Applies the function to the error of this computation.

mapIt :: ((b → ()), (e → ()), (a → b)) → (a → ())

Returns a new function that applies fn to whatever value it gets and then applies cont to that. If an error occurs in fn, then we will catch it and fail with it.

Note: This allows breaking out of the monadic control flow by throwing in a map, but it is very important that we don't bring down an entire application by one Async computation having an error in it.

new :: ((a → (), e → ()) → c) → Async c e a

Creates an Async computation from the provided thunked computation, which will be called with callbacks for a result or error when the Async computation is forked/ran.

run :: Async c e a → ()

Forks the computation and throws away the results.

Useful for when you were using the Async results to do side effects that could throw errors in a tap and wanted to catch them using chainFail/catch.

seqL :: Async c e a → Async c e b → Async c e a

Sequences Async computations, keeping the value of the one on the left. The computations are ran concurrently.

seqR :: Async c e a → Async c e b → Async c e b

Sequence Async computations, keeping the value of the one on the right. The computations are ran concurrently.

tap :: Async c e a → (a → ()) → Async c e a

Tap into the Async computation at a certain point to perform a side effect. This should be used with care and mainly only by the consumer of an Async computation.

tapFail :: Async c e a → (e → ()) → Async c e a

Tap for failures.

toObservable :: Async c e a → Observable e a

Creates an Observable that will run this computation for every observer to produce a single value for that observer and complete, or will end with an error if the computation fails.

This can be useful for running actions in response to each event emitted by an Observable by chaining/binding a function to it that returns Observables created by calling this method on an Async.

Note that this does not break the laziness of an Async computation as Observables are also lazy.

Remember to call .share as appropriate if you only want the Async computation to run once for all observers.

toPromise :: Async c e a → Promise a e

This is the same as forking the computation, but you get back a Promise for the result.

MonadicJS.Async.AsyncFirst

Written By: Joel Dentici

Written On: 6/25/2017

Holds a set of AsyncComputations.

fork :: AsyncFirst e a → (a → b, e → c) → b | c

This overrides the AsyncComputation fork to fork all the Async computations and keep the result of whatever finishes first.

new :: [Async c e a] → Async c e a

Constructs an AsyncFirst

MonadicJS.ConcurrentFree

Written By: Joel Dentici

Written On: 7/19/2017

Free monads over any algebraic data type that preserve concurrent semantics of Applicative and Functor during interpretation.

alt :: Free f a → Free f b → Free f (a | b)

Alternative composition. During interpretation, we attempt to interpret this Free Monad. If that results in an error, we interpret the specified Free Monad instead.

You must include Control.interpreter in your interpreter list to use this, or you will get an error at runtime.

ap :: Free f a → Free f (a → b) → Free f b

Reversed arguments of app.

app :: Free f (a → b) → Free f a → Free f b

Applicative application of a function in a Free monad to a value in a Free monad.

catch :: Free f a → (e → Free f b) → Free f (a | b)

If the computation represented by this Free monad fails, then the specified handler will be applied to the error in an attempt to recover. The handler maps an error into a new computation.

You must include Control.interpreter in your interpreter list to use this, or you will get an error at runtime.

chain :: Free f a → (a → Free f b) → Free f b

Monadic chaining/binding of a value in a Free monad to a function that returns a Free monad.

chainFail :: Free f a → (e → Free f b) → Free f (a | b)

You must include Control.interpreter in your interpreter list to use this, or you will get an error at runtime.

Alias for catch

combineTransformations :: Monad m ⇒ forall a. [f a → m (m a)] → (f a → m (m a))

Combines a list of transformations into a single transformation.

In order for this to work, each transformation must return an undefined result for any (f a) it cannot handle. This is easily accomplished with default: constant(undefined) or default: _ => undefined or default: _ => {} in the type case analysis.

If no transformation exists for a value, then an InterpreterError is thrown.

empty :: Free f ()

A Free Monad with no value. Uses the control primitive throwE to ensure that chained functions will not be applied, thus satsifying empty >>= f = empty.

fail :: e → Free f a

Results in a failed computation with the specified error.

foldConcurrent :: Monad m ⇒ Free f a → (Type m, (forall x. f x → m (m x))) → m a

Interpret this Free monad into the specified monad using the specified transformation.

foldConcurrent :: Monad m ⇒ Type m → (forall x. f x → m (m x)) → Free f a → m a

Interpret a Free monad over f using a transformation from f to m m, where m is the monad we are interpreting into.

interpret :: MonadFail m, All m ⇒ (Type m, ...Interpreter) → Free f a → m e a

Interprets a Free monad using multiple interpreters, typically one for each ADT that is summed into f, into the specified monad.

Each interpreter can run setup and cleanup actions. Two cleanup methods are required: one for a normal case and one for an error case. If either cleanup method itself fails, then the error for that is returned. If only the transformation fails, then the error for that is returned.

The monad being interpreted into must be a MonadFail and All, meaning it should provide a fail method for errors, a chainFail method to catch errors, and an all method to sequence a list of actions.

Interpreter :: Object

An Interpreter is an object satsifying the following interface:

.setup :: MonadFail m => () -> m e () Perform actions prior to interpretation

.transform :: MonadFail m => (f x, f x -> m e x) -> m e x Transform an ADT to a monadic action. The second argument to transform contains all transformations and can be used with foldConcurrent to interpret "sub-statements".

.cleanupSuccess :: MonadFail m => x -> m e () Perform cleanup after successful interpretation

.cleanupFail :: MonadFail => e -> m (e | e2) () Performs cleanup after failed interpretation

This is the preferred interface, instead of just providing a transformation.

liftF :: f a → Free f a

Put a value in f context into a Free f context

map :: Free f a → (a → b) → Free f b

Maps a function over the value in the Free monad.

mapFail :: Free f a → (e → e2) → Free f a

Maps the error in a Free monad computation. This is of course bypassed if the computation does not result in an error.

This cannot be used to recover from an error, only for mapping them. See chainFail and catch for error recovery.

You must include Control.interpreter in your interpreter list to use this, or you will get an error at runtime.

seqL :: Free f a → Free f b → Free f a

Applicative sequencing from left-to-right, keeping the left value.

seqR :: Free f a → Free f b → Free f b

Applicative sequencing from left-to-right, keeping the right value.

unit/of :: a → Free f a

Put a pure value into Free f context

zero :: () → Free f ()

Returns Free.empty

MonadicJS.ConcurrentFree.Control

Written By: Joel Dentici

Written On: 7/20/2017

Provides control flow primitives for Free monads that require access to execution.

Note that this is what gives ConcurrentFree its Alternative instance, so you must include it in your interpreter list to use Alternative composition with ConcurrentFree.

catch e a :: Object

A catch is an object providing a catch method that accepts a handler for errors.

catch :: () -> (e -> Free Control a) -> Free Control a

You don't need to supply your own catch. It is what is returned by applying tryF. You supply a handler to that catch. This is purely so try-catch looks like normal JS.

delay :: Free Control ()

Represents a delay in further computation.

This can be useful at the beginning of a Free program to force waiting before executing the first statement, which might be a plain old JS statement with a side effect that we did not intend to run yet. It is unimportant for "pure" side effects that occur in a monad.

We can't get this from just using F.of since we immediately apply the chained function.

fromAsync :: Async c e a → Free Control a

Useful if you will be interpreting to Async.

When interpreted into an Async, it just spits out the Async it is holding

fromPromise :: Promise e a → Free Control a

Wraps the promise in an Async and then applies fromAsync to that.

throwE :: e → Free Control ()

Throws an error.

tryF :: Free f a → catch e b → Free Control (a | b)

Applying tryF to a Free Monad value will return a catch that accepts a handler for the errors that may be generated by interpreting that Free Monad value.

The result of applying the catch to a handler is a Free Monad whose result type is either the type of this Free Monad or the type of the Free Monad returned by the handler.

Returning a catch is purely so that this looks like normal JS.

This is unnecessary to use directly as the chainFail, chainMap, catch methods on ConcurrentFree all use it. It might still be useful if you prefer the standard try-catch look.

MonadicJS.Do

Written By: Joel Dentici

Written On: 6/30/2017

Provides ability to use do notation without relying on generators. This leads to fancier code and the ability to use monads that apply their bound function more than once, like list.

This module provides a function that can be called to install a hook into the node module loader, which will cause any later require() calls to have their module's source processed through this module. The transforming function itself is exported so you can write a simple source-to-source compiler if you prefer that.

loadDo :: (string, bool) → ()

Hooks into the node module loader and registers the specified extension to be pre-compiled by the do-notation transformer.

The default extension used when none is specified is '.ejs'

The second argument can be used to get verbose output from this function: Level 0 - Errors only Level 1 - Level 0 + Loading messages & compilation time Level 2 - Level 1 + Compilation output

MonadicJS.Do.Analyze

Written By: Joel Dentici

Written On: 7/10/2017

Performs analysis on do notation blocks in an AST, looking for pieces that can be optimized to use applicative, rather than monadic, application and sequencing.

The resulting AST has nodes that can be used in applicative style marked as such.

analyze :: AST → AST

Performs analysis on the provided AST.

TODO: Implement this.

MonadicJS.Do.Generate

Written By: Joel Dentici

Written On: 7/10/2017

Generates JavaScript output from a Transformed AST.

generate :: AST → string

Maps the AST to a string by traversing it and mapping each node that is encountered to a string.

MonadicJS.Do.Lexer

Written By: Joel Dentici

Written On: 7/1/2017

This module performs lexical analysis on an input string according to a provided lexical grammar.

MonadicJS.Do.LexicalGrammar

Written By: Joel Dentici

Written On: 7/1/2017

This module defines the lexical grammar (parts of the CFG that can be recognized by regular expressions) for a subset of JavaScript's lexical gramar.

MonadicJS.Do.ParseDo

Written By: Joel Dentici

Written On: 7/10/2017

This module defines the parser for do notation and expression blocks.

This should be used in conjunction with the lexer module and the provided lexical grammar.

infixLeft :: (Parser Token string, Parser Token AST) → Parser Token AST

Creates a parser for an infix operator(s) that is left associative.

infixRight :: (Parser Token string, Parser Token AST) → Parser Token AST

Creates a parser for an infix operator(s) that is right associative.

operators :: Map string (Parser Token any) → Parser Token string

Creates a single parser from a map from operator names to operator parsers. Each parser in the map is made to yield its name as its result.

postfix :: (Parser Token string, Parser Token AST) → Parser Token AST

Creates a parser for a postfix operator(s).

prefix :: (Parser Token string, Parser Token AST) → Parser Token AST

Creates a parser for a prefix operator(s).

topLevel :: (a, Parser Token AST) → Parser Token BinaryExpression

Creates a parser for the top level precedence operators in JavaScript. These are the member access and function application which both have weird syntax compared to other operators.

MonadicJS.Do.Transform

Written By: Joel Dentici

Written On: 7/10/2017

Provides a function to replace do-blocks, if-blocks, and other specialized syntax (non-js operators) with valid js syntax.

transform :: (AST, string) → AST

Transforms the AST in the manner described above.

transformBinaryExpr :: string → (string, AST, AST) → AST

Transforms the binary expression. If its operator is one of those in exprOps, then we transform it to the appropriate function application

transformDoBlock :: (string, [AST]) → AST

transformUnaryExpr :: string → (string, AST) → AST

Transforms return expressions to applications of the current monad's "of" function. If we are not in a do-block, then the return is left as is and will become a statement in the output JS.

All other unary operator expressions are returned unchanged.

MonadicJS.Do.TransformJS

Written By: Joel Dentici

Written On: 7/10/2017

This module provides a function to transform JavaScript source that contains do and expr blocks to an equivalent one with those blocks mapped to actual JavaScript syntax.

This relies on lexing the source, scanning until a block is found, emitting tokens that are not part of a block immediately to the output buffer.

Once a block is found, we begin parsing at the current input position. The AST of the parsed block is then analyzed and transformed to get a new AST with only JavaScript syntax. That AST is finally mapped back to JavaScript source code by the generator.

After a block has been fully transformed, we begin scanning and immediate re-emitting until we find another block.

The resulting output buffers are concatenated and returned.

isDo :: ([Token], int) → bool

Checks if we are at a possible do block.

isExpr :: ([Token], int) → bool

Checks if we are at a possible expr block.

isX :: ([Token], int, string, string) → bool

Checks if the current position is the beginning of some type of phrase.

transformJS :: string → Either string string

Transforms the input source code in the manner described above.

If an error occurs while parsing a do-block or expr block, then it will be returned after being formatted into a readable string. Otherwise, the resulting source code is returned. The first error to occur will stop any further transformation.

MonadicJS.Either

Written By: Joel Dentici

Written On: 6/20/2017

Defines the Either monad.

unit/of :: a → Right a

Puts a value into Either context.

MonadicJS.Either.Left

Written By: Joel Dentici

Written On: 6/20/2017

The Left constructor

ap :: Left a → Either e (a → b) → Left a

Applicative application for fantasy-land

app :: Left e () → Either e a → Left e ()

Applicative application

bind :: Left c → (a → Either c b) → Left c

Doesn't apply the function per Either semantics.

chain :: Left c → (a → Either c b) → Left c

Alias for bind. Provided for fantasy-land compliance.

doCase :: Left a → (a → b) → b

Applies the function to the value in the Left

map :: Left c → (a → b) → Left c

Doesn't apply the function per Either semantics.

new :: a → Left a

Construct a Left

MonadicJS.Either.Right

Written By: Joel Dentici

Written On: 6/20/2017

The Right constructor

ap :: Right a → Either (a → b) → Left b

Applicative application for fantasy-land

app :: Right (a → b) → Either a → Left b

Applicative application

bind :: Right a → (a → Either c b) → Either c b

Apply the function to the value contained in this Right.

chain :: Right a → (a → Either c b) → Either c b

Alias for bind. Provided for fantasy-land compliance.

doCase :: Right a → (a → b) → b

Apply the function to the value contained in this Right.

map :: Right a → (a → b) → Right b

Apply the function to the value contained in this Right.

new :: a → Right a

Construct a Right

MonadicJS.FunctionExtensions

Written By: Joel Dentici

Written On: 7/19/2017

Makes Function compatible with this library.

WARNING: This modifies the Function prototype so you should always unload it when done. You may still mess other code up if you use these extensions in an asynchronous section of code.

NOTE: Using the do-notation/expr language extension will automatically load these extensions. That is because they include kleisi composition, which it provides an operator for.

alt :: Alternative f ⇒ (a → f b) → (a → f c) → a → f (b | c)

This lifts the alternative combinator for an Alternative to work on alternative returning functions. Note that this will always evaluate both functions to use the alternative instance of their return values. As long as your alternative is side-effect free, this won't cause any problems. If it is not and those side-effects are critical (ie, not console.logs or something similar), you might wind up with corrupt data somewhere.

arrow :: Monad m ⇒ (a → m b) → (b → m c) → a → m c

Left-to-right Kleisi composition of monadic functions.

chain :: (a → b) → (b → (a → c)) → a → c

map :: (a → b) → (b → c) → a → c

Sequencing of functions.

The Haskell definition is composition of functions but we define map with its arguments backwards for all our Functors so it can live on the object, which means out map = flip haskellmap = sequence

MonadicJS.Maybe

Written By: Joel Dentici

Written On: 6/20/2017

Defines the Maybe monad.

nullable :: a → Maybe a

Puts a value into Maybe context. If it is null or undefined, Nothing is returned.

unit/of :: a → Just a

Puts a value into Maybe context.

zero :: () → Nothing

MonadicJS.Maybe.Just

Written By: Joel Dentici

Written On: 6/20/2017

The Just constructor

alt :: Just a → Maybe b → Just a

ap :: Just a → Maybe (a → b) → Maybe b

Applicative application, for fantasy-land.

app :: Just (a → b) → Maybe a → Maybe b

Applicative application.

bind :: Just a → (a → Maybe b) → Maybe b

Apply the function to the value contained in this Just.

chain :: Just a → (a → Maybe b) → Maybe b

Alias for bind. Provided for fantasy-land compliance.

doCase :: Just a → (a → b) → b

Apply the function to the value contained in this Just.

map :: Just a → (a → b) → Just b

Apply the function to the value contained in this Just.

new :: a → Just a

Construct a Just

MonadicJS.Maybe.Nothing

Written By: Joel Dentici

Written On: 6/20/2017

The Nothing type

alt :: Nothing → Maybe a → Maybe a

ap :: Nothing → Maybe (a → b) → Nothing

Applicative application, for fantasy-land.

app :: Nothing → Maybe a → Nothing

Applicative application.

bind :: Nothing → (a → Maybe b) → Nothing

Doesn't apply the function per Maybe semantics.

chain :: Nothing → (a → Maybe b) → Nothing

Alias for bind. Provided for fantasy-land compliance.

doCase :: Nothing → (() → b) → b

Applies the function

map :: Nothing → (a → b) → Nothing

Doesn't apply the function per Maybe semantics.

MonadicJS.Parser

Written By: Joel Dentici

Written On: 7/3/2017

Applicative Parser combinators for JavaScript.

The parsers are LL() and uses a modified version of the parsing algorithm given by Frost, Hafiz, and Callaghan to handle left recursion and provide memoization of parse results. This is an LL parser, unlike the parser they give so it only returns the left-most parse (derivation) according to the grammar it is parsing.

These parsers do not require a separate lexical analysis step, but their performance can be improved by using one. The combinators can be used to perfrom this lexical analysis step, but it will probably be more efficient to write a procedure specific to this.

It implements the following Fantasyland algebras: Functor Apply Applicative Alt Plus Alternative Chain Monad

We also alias our names for the operations of the above algebras, as well as providing aliases for names specific to parsing.

The names for some operations were taken from Parsimmon.

runParser :: (Parser t a, bool?) → ([t], int?) → Either ParseError (ParseResult a)

Runs the provided parser on the provided input. Either a ParseError or ParseResult a is returned depending on whether the parser failed or succeeded. Both contain the position in the input last parsed. ParseError additionally contains an Error and ParseResult contains a value of type a.

MonadicJS.Parser.Parser

Written By: Joel Dentici

Written On: 7/5/2017

Parser type. Implements applicative, alternative, functor, and monad algebras.

Parsers automatically detect and fail left recursion infinite descent of a parser, so that other parsers can be tried.

Parsers can be memoized. This increases parsing efficiency for grammars where backtracking is necessary (ie ambiguous grammars).

all :: Parser t [t]

A parser that will consume any remaining input.

It is not an error to already be at the end of the input, but an empty result will be returned if this is the case.

alt :: Parser t a → Parser t b → Parser t (a | b)

Alternative Applicative Functor choice application

Returns a parser that:

Applies this parser first. If it fails, then the provided parser is applied. The result of the last applied parser is returned.

any :: Parser t t

A parser that will consume the next token of input and return it as its result, no matter what it is.

If there is no input left, then an error is returned.

ap :: Parser t a → Parser t (a → b) → Parser t b

Applicative functor application, conforming to the fantasy-land spec.

Unfortunately, the fantasy-land spec has the parameters backwards from the Haskell function, which makes applicative application unnatural. Use app for a more natural applicative interface.

app :: Parser t (a → b) → Parser t a → Parser t b

Applicative Functor application

Returns a parser that:

Applies a function in parser context to the result of a parser. If the function is curried and has more arguments, then ap can be changed.

bind :: Parser t a → (a → Parser t b) → Parser t b

Monadic bind

Returns a parser that:

First applies this parser to get a result. If successful, the provided function is applied to the result to get a new parser. That parser is then applied to get the result.

You should use the applicative interface in cases where you don't need to make context-sensitive decisions. Obviously if context is required to parse, the monadic interface must be used as it is the only combinator that allows decisions to be made at runtime.

canReuse :: LeftRecContext → LeftRecContext → bool

Checks whether a result can be reused in the current parsing context.

chain :: Parser t a → (a → Parser t b) → Parser t b

Alias for bind. Provided for fantasy-land compliance.

cons :: a → [a] → [a]

Contructs a list from a head element and a tail list.

empty :: Parser t ()

A parser with no result. This parser always succeeds without consuming any input.

eof :: Parser t ()

A parser that expects to see the end of input.

If EOF has been reached, then an empty result is returned, otherwise an error is returned.

fail :: Error → Parser t ()

Returns a parser that always fails with the provided error.

Fail :: int → Error → ParseError

See ParseError. Applies ParseError to p, e and then wraps the return value in an Either context.

fallback :: Parser t a → b → Parser t (a | b)

Returns a parser that first tries this parser, but always returns the provided value when this parser fails.

Equivalent to this.alt(Parser.of(value))

findToken :: (t → bool) → string → Parser t t

Returns a parser that consumes input until it matches an input token with the provided predicate. If no match occurs, then an error is raised.

This is useful in conjunction with lookahead when parsing input that has been lexed. For raw input, regex is probably more useful.

getlrec :: LefRecContext → int → int → LeftRecContext

Returns the LeftRecContext that should be used:

If the oldPos is not the newPos (in other words, the prior parser consumed input), then the LeftRecContext should be reset, otherwise the same one is passed down.

lookahead :: Parser t a → Parser t bool

Returns a parser that will check if the provided parser matches the upcoming input.

If it does, true is returned, otherwise false is returned. The resulting parser does not consume input and never fails (in the sense of throwing an error).

lookup :: Parser t a → int → LeftRecContext → Map (Parser t a) (Map int (Either ParseError [(ParseResult a), LeftRecContext])) → ParseResult a | null

Tries to find a valid result in the memoization table for the provided parser.

many :: Parser t a → Parser t [a]

Alternative Applicative Functor many

Returns a parser that:

Applies this parser zero or more times to get a list of the results that this parser returns.

map :: Parser t a → (a → b) → Parser t b

Functor map

Returns a parser that:

Applies this parser to the input. If it succeeds, the provided function is applied to its result and the result of that application is returned.

memoize :: Parser t a → bool? → any? → Parser t a

Returns an equivalent parser that memoizes results, up to curtailment of left recursion.

This should generally be applied to non-terminals. Applying it too liberally can actually cause worse performance.

The optional boolean argument tells memoize whether the original parser is even or odd (based on how many parsers it chains together, only at the top level). This is used to give the correct left-most parse when left-recursion occurs because it lets us avoid an off-by-one error when we attribute curtailment too deep by assuming an even parity.

The optional name argument allows you to provide the value that will be used in internal maps and sets. Absent it, the parser itself will be used. It may be possible to get better performance by using an integer, for example than an object.

mergeUps :: int → int → Set a → Set a → Set a

Merges the provided up contexts (sets of parsers that led to curtailment due to left recursion):

If oldP is not the newP (some input was consumed in the second parser), then the first context is returned. Otherwise, the contexts are merged.

new :: ([t] → int → LeftRecContext → State ParseState (Either ParserError (ParseResult a))) → Parser t a

Constructs a parser from the provided function.

of/unit :: a → Parser t a

Returns a parser whose result is the value provided (always). This parser always succeeds without consuming any input.

or :: Parser t a → Parser t b → Parser t (a | b)

Alias for alt. Provided as the name is more meaningful in the domain of parsing.

ParseError :: int → Error → ParseError

Returns a ParseError, representing a parse that failed after consuming tokens up to (p - 1) with the provided error.

Parser :: ([t] → int → LeftRecContext → State ParseState (Either ParserError (ParseResult a))) → Parser t a

Constructs a Parser from the provided function.

ParseResult :: int → a → ParseResult a

Returns a ParseResult, representing a parse that has consumed tokens up to (p - 1) and has yielded the value x.

pruneContext :: Set (Parser t any) → Map (Parser t any) int → Map (Parser t any) int

Removes entries from the provided LeftRecContext that do not appear in the cutailment set.

recursive :: (() → Parser t a) → Parser t a

Creates a Parser that applies the provided function the first time the parser is used to get a parser to parse with. That parser is then used to parse the current and all subsequent inputs when the returned parser is used.

This allows the construction of recursive grammars, so that parsers can refer to ones that have not yet been defined.

regexTerm :: RegExp → string → Parser string [string]

Recognizes strings in the input matching the provided regular expression. The result when successful is a list of matches, which is what is returned by the JavaScript string match function.

Aliases: regex

result :: Parser t a → b → Parser t b

Returns a parser that runs this parser first, but always maps its result to the provided value.

Useful with stringTerm parsers that only recognize a single value, but you may want a static, semantically meaningful result.

runParser :: Parser t a → [t] → int → LeftRecContext → State ParseState (Either ParseError (ParseResult a))

Runs the parser on the provided input, at the provided position, given the provided LeftRecContext (left recursion depth map).

Returns a State monad value that can be applied to the current (including initial) ParseState to get the parser's result.

Note: This is used internally. Use Parser.runParser to run the outermost parser for your grammar. Doing so will also run the State monad, allowing you to inspect the results.

sepBy :: Parser t a → Parser t b → Parser t [a]

Returns a parser that tries to repeat applications of this parser, separated by applications of the provided parser.

This is equivalent to looking for this parser followed by the provided parser or the empty parser an [0, infinity) (many) number of times.

sepByPlus :: Parser t a → Parser t b → Parser t [a]

Same as sepBy, but expects this parser to match at least once. Essentially the same as the distinction between some and many.

seqL :: Parser t a → Parser t b → Parser t a

Applicative Functor sequential application

Returns a parser that:

First applies this parser, then the provided parser, dropping the result of the provided parser.

seqR :: Parser t a → Parser t b → Parser t b

Applicative Functor sequential application

Returns a parser that:

First applies this parser, then the provided parser, dropping the result of this parser.

showError :: ParseError → ([t], int) → string

Returns a formatted error message from the provided error.

The input to the parser should be provided, along with a context value that determines how much input around the position where the error ocurred should be shown.

skip :: Parser t a → Parser t b → Parser t a

Alias for seqL. Provided as the name is more meaningful in the domain of parsing.

some :: Parser t a → Parser t [a]

Alternative Applicative Functor some

Returns a parser that:

Applies this parser at least once to get a list of the results that this parser returns.

stringTerm :: string → Parser string string

Recognizes the provided term.

Can be thought of as a CFG terminal.

Aliases: term

Succeed :: int → a → Either ParseError (ParseResult a)

See ParseResult. Applies ParseResult to p, x and then wraps the return value in an Either context.

then :: Parser t a → Parser t b → Parser t b

Alias for seqR. Provided as the name is more meaningful in the domain of parsing.

tokenTerm :: (t → bool) → Parser t t

Recognizes tokens in the input which the provided predicate returns true for. The matching token is returned when successful.

This is useful when you perform lexical analysis separately from parsing, as you cannot use the string or regex terminal parsers on tokens (obviously).

Aliases: token

trim :: Parser t a → Parser t b → Parser t a

Returns a parser that applies (around, this, around) in sequence, keeping the results of this.

Equivalent to this.wrap(around, around) or around.seqR(this).seqL(around).

wrap :: Parser t a → Parser t b → Parser t c → Parser t a

Returns a parser that applies (prev, this, next) in sequence, keeping the results of this.

Equivalent to prev.seqR(this).seqL(next)

zero :: () → Parser t ()

Constant function returning a failing parser.

This is the zero (additive identity) of the MonadPlus/Alternative monoid, satisfying annihilation: zero() >>= f = zero(), zero().app(x) = zero()

Note that empty is not a valid zero in any way as it does not satisfy the alternative laws -- namely empty <|> u is empty, but it would be u if empty was a zero. It definitely does not satisfy annihilation.

Despite this, zero will probably find less use than empty, which can actually be useful since it succeeds. For example, the implementation of sepBy uses empty, but it would not work with zero, because alternating with zero is literally the same as not using it (because it is an identity in every way). But empty succeeds and thus can provide its own semantics in the alternative chain.

Exists for fantasy-land compatability.

MonadicJS.State

Written By: Joel Dentici

Written On: 7/3/2017

The State monad.

ap :: State s a → State s (a → b) → State s b

Applicative application for fantasy-land

app :: State s (a → b) → State s a → State s b

Applicative application

bind :: State s a → (a → State s b) → State s b

Monadic bind. The result, when ran, will apply the function in this State to the provided state to get a result and updated state. The provided function is applied to the result to get a new State and the function in the resulting State is applied to the updated state.

Thus, the state is threaded through to the provided function as well as the value.

chain :: State s a → (a → State s b) → State s b

Alias for bind. Used for fantasy-land compliance.

get :: State s s

Returns a new State whose computation returns the provided state as its value, and leaves the state unchanged.

map :: State s a → (a → b) → State s b

Functor map for State.

Maps the function over this state by applying the provided function to the value inside this state, without affecting the current state.

modify :: (s → s) → State s ()

Returns a new State whose computation applies the provided transformation to the current state and returns that as the new state.

new :: (s → [t, s]) → State s t

Constructs a new State_ value.

put :: s → State s ()

Returns a new State whose computation replaces the current state with the state provided to put.

runState :: State s t → s → [t, s]

Runs the state monad with the provided state.

State :: (s → [a, s]) → State s a

Constructs a State from a state threading computation.

unit/of :: a → State s a

Puts a value into a stateful context.

Does not change the state.

MonadicJS.Utility

Written By: Joel Dentici

Written On: 6/20/2017

Utility functions for working with monads, applicatives, alternatives, and just functional stuff in general.

all :: Applicative f ⇒ (Type f, [f a]) → f [a]

Collects the results of a list of applicative actions into a list. This is more efficient than mapM (Type f, id), because it uses array push on the result list rather than creating intermediate arrays.

CaseAnalysisError :: Error

Thrown when an error occurs during case analysis.

CaseClass :: Object { case :: CaseClass → Map string (...any → any) → any }

Objects that extend this class implement a doCase method that calls a function with their members.

Case analysis is performed using caseOf when case is called on the object.

caseOf :: (Object, Map string (any → any)) → any

Perform case analysis on an object, dispatching to the appropriate type handler in the provided switch map, or a default handler. If no default handler is provided and no type matches, then a CaseAnalysisError is thrown.

If the object is "caseable", then it has a doCase method that can call the handler with its members.

Other objects are supported, but the object itself will be passed to the handler (though ES6 object destructuring can be pretty powerful there).

constant :: a → b → a

When applied to a value, returns a function that will always return that value, regardless of what it is applied to.

doM :: Monad m ⇒ (() → Iterator) → m a

Do notation helper for monads. Taken from: https://curiosity-driven.org/monads-in-javascript

Example Usage:

const result = doM(function() {
const fst = yield Either.right(5);
const snd = yield Either.right(11);
return Either.unit(fst + snd);
});

Note: It is recommended that you use the do-notation language extension provided, instead of this. Using this weird generator fu can lead to problems since generators cannot be reused, but a do-notation block is supposed to be a value semantically, which means it should be able to be reused. The generator approach also cannot accommodate monads like the list monad that apply their bound function more than once.

exists :: MonadFail m ⇒ m (Maybe a) → m a

Flattens a monadic action that contains a Maybe using the monad's fail method with a Skip error.

filterM :: Consable t, Applicative f ⇒ (Type f, (a → f bool)) → t a → f (t a)

Filters a specified list by using a predicate with results in the specified applicative. Returns the filtered list in the specified applicative.

foldlM :: Foldable t, Monad m ⇒ (Type m, (b, a) → m b) → b → t a → m b

Monadic fold over a structure, from left to right.

foldrM :: Foldable t, Monad m ⇒ (Type m, (a, b) → m b) → b → t a → m b

Monadic fold over a structure, from right to left.

forever :: Monad m ⇒ m a → m ()

Repeat a monadic action an infinite number of times. Note that this will never return a result nor will it ever allow another action to be sequenced after it.

guard :: Alternative f ⇒ (bool, Type f) → f ()

Guards further MonadPlus binding/sequencing when the provided condition is false, due to the law that empty >>= f = empty

id :: a → a

Always returns the value it is applied to.

liftMaybe :: MonadFail m ⇒ (Type m, (a → Maybe b)) → a → m b

Lifts a partial function into the context of any monad that has failure semantics. The resulting function's values will either contain the value in the Maybe, or have a Skip error.

mapM :: Consable t, Applicative f ⇒ (Type f, (a → f b)) → t a → f (t b)

mapM defined to work over any Consable structure and with Applicatives.

TODO: Implement the more generic Traversables and traverse and define this in terms of that

replicateM :: Applicative f ⇒ (Type f, int, f a) → f [a]

Repeats the specified action cnt times and collects the results into a list.

resume :: MonadFail m ⇒ m a → m a

Stops the "skipping" of a action by handling the error that skipping introduced.

If the action was not skipped, this has no effect (just like normal catching), and if the action had any error other than the skipping one, then it will be propagated.

retry :: MonadFail m ⇒ int → (...any → m a) → ...any → m a

Wraps a monadic computation/function so that if it fails, it is automatically retried a specified number of times.

seqAll :: Monad m ⇒ (Type m, [m a]) → m [a]

Like all, but uses monadic sequencing instead of applicative sequencing. This enforces sequential execution for Monads whose Applicative instance is concurrent. This is useful when prior actions might

seqMapM :: Monad m ⇒ (Type m, a → m b) → [a] → m [b]

mapM restricted to lists and using monadic chaining.

skip :: Skip

A value of the type Skip. This can be used with m.fail for any MonadFail m.

Another point in the monadic 'program' can use resume(v) to end the skipping.

Skip :: Object

A special type of object that can be used to fail an action, therefore skipping the rest of it, with the intention that the caller will handle this failure.

unless :: Applicative f ⇒ (bool, f ()) → f ()

Performs the specified action when the specified condition is false.

when :: Applicative f ⇒ (bool, f ()) → f ()

Performs the specified action when the specified condition is true.

zip :: [a] → [b] → [(a,b)]

Zips corresponding elements from two lists into a list of pairs of those elements.