Expand home page. authored by Ladislav Lhotka's avatar Ladislav Lhotka
...@@ -25,13 +25,13 @@ Gonads") how the powerful concept of ...@@ -25,13 +25,13 @@ Gonads") how the powerful concept of
"Monad") can be implemented in JavaScript. "Monad") can be implemented in JavaScript.
So I was wondering whether a decent monadic parser could be written in So I was wondering whether a decent monadic parser could be written in
CoffeeScript. The result is Comparse, a monadic parsing library, which CoffeeScript. The result is _Comparse_, a monadic parsing
is described in the rest of this text. Frankly, I didn't expect to get library. Frankly, I didn't expect to get something nearly as elegant
something nearly as elegant as the Haskell parsers mentioned above, as the Haskell parsers mentioned above, primarily because Haskell has
primarily because Haskell has special syntactic sugar for monad special syntactic sugar for monadic programming (the “do”
programming (the “do” notation). Much to my surprise, monadic notation). Much to my surprise, monadic functions and their
functions and their combinations can be written quite nicely in the combinations can be written quite nicely in the CoffeeScript syntax
CoffeeScript syntax (but maybe I am just weird and biased). (but maybe I am just weird and biased).
The implementation takes into account the lack of tail recursion The implementation takes into account the lack of tail recursion
optimization in JavaScript, so recursive functions are mostly optimization in JavaScript, so recursive functions are mostly
...@@ -39,6 +39,55 @@ rewritten using loops. Also, since JavaScript is _not_ a pure ...@@ -39,6 +39,55 @@ rewritten using loops. Also, since JavaScript is _not_ a pure
functional language, side effects and non-local variables are used in functional language, side effects and non-local variables are used in
a few places for improving efficiency. a few places for improving efficiency.
Getting Started
===============
It is not necessary to understand
[monads](http://en.wikipedia.org/wiki/Monad_%28functional_programming%29)
in order to be able to use the _Comparse_ library. It is just
sufficient to remember that a _parser_ constructed with this library
is a function in a context, where the context is simply an offset in
the input string where the function is supposed to start parsing.
The essential pattern in parser construction is connected with the
`bind` method and looks like this:
p.bind f
The `bind` method returns a new parser that applies two parsers
sequentially. The first parser is the receiver `p` of the `bind`
method. However, the argument of `bind`, denoted `f`, is _not_ the
second parser: instead, `f` is a _function_ that returns a parser. Why
is that? It allows us to use the result of `p` in further processing,
and indeed, the argument of `f` is exactly the result of the parser `p`.
The `bind` method works like this:
1. The receiver (parser `p`) is applied first. If it fails (its result
is `null`), then the combined parser returned by `bind` fails as
well.
1. Otherwise, the result of parser `p` is fed as the argument to
function `f` that returns a parser, say `q`. The result of the
combined parser is then the result of `q`.
The argument of `bind`, function `f`, may of course be defined in a
separate assignment. Quite often, however, the argument `f` is
specified inline. The bind expression then looks in the CoffeeScript
syntax like this:
p.bind (res) -> fbody
Of course, the argument function of `bind` may completely ignore the
result of parser `p`. In this case, the `bind` expression can be
written simply as follows:
p.bind -> fbody
Other parser combinators and predefined parsers provided by the
_Comparse_ library are described in the Literate CoffeeScript
[source](comparse).
* [Annotated source code](comparse) * [Annotated source code](comparse)
* [Example parsers](examples) * [Example parsers](examples)