Accumulator
As noted in the overview, one uses an accumulator to collect information about sequentially numbered sections, cross-references, tables of content, etc., then uses a second accumulator to render the source text with these features. Accumulators are made of up of reducers and folds:
A Reducer
is a name for the type of the first argument of a fold. Consider a reducer of the form
It fits into a fold of the form
Let transform
have type StateReducer state a b
. Define
The type of this function is
To restate in plainer English, an Accumulator state a b
takes as input a State a b
and a List a
and returns a tuple consisting of an updated State a b
and another list, one of type List b
.
Accumulator.parse
Let us discuss the accumulators used in MiniLatex. The first of these is Accumulator.parse
. Its function is to take a LatexState
and a list of paragraphs, i.e., a List String
, and produce an updated LatexState
and a List (List LatexExpression)
. Each element of the latter is a List LatexExpression
representing the application of the MiniLatex parser to a paragraph.
The Accumulator.parse
function applies a List.foldl
to a pair consisting of an initial LatexState
and an empty list using a parseReducer
. The latter is defined as follows:
The parseReducer
takes as input a string, representing a logical paragraph of source text, and a pair consisting of a LatexState
and a List (List LatexExpression
. It parses the string and computes a new LatexState
using latexStateReducer
:
We discuss this function later on. The return value of the parseReducer
is a pair consisting of the new LatexState
and inputList with the parsedInput appended.
Accumulator.render
Accumulator.render renderer
is an accumulator which takes a LatexState
and a List (List LatexExpression)
as input, and produces a new LatexState
and List a
as output. The nature of a
depends on the renderer
function used:
The expression renderReducer renderer
is a reducer of type
It operates as follows:
Compute a new
LatexState
by applyinglatexStateReducer
to (a) the given list ofLatexExpressions
and (b) theLatexState
coming from the first element of the second argument, a tuple of type(LatexState, List a)
Apply the
renderer
to the new state computed in the previous step and theList LatexExpression
given by the first argument.Return a tuple consisting of the updated
LatexState
and theinputList
with the newly rendered text appended.
LatexStateReducer
The purpose of the latexStateReducer
is to update a given LatexState
using the information contained in a List LatexExpression
, i.e., the parse result of a paragraph.
This a fairly complex reducer. In brief, it looks at the first LatexExpression
in the List LatexExpression
representing a given paragraph, then uses the function info
to compute a record, theInfo
, which extracts certain information from the paragraph. For example, if the paragraph is \section{Introduction}
, the theInfo
will contatin fields name = section
and typ = macro
. The call latexStateReducerDispatcher theInfo
uses a dictionary lookup to produce a function of type LatexInfo -> LatexState -> LatexState
from theInfo
. Therefore the value of the expression
is of type LatexState
, in accord with what one reads from the type annotation of latexStateReducer parsedParagraph latexState
.
Let's see how this works in a simple example:
Now the dispatcher looks like this
where the dictionary has type
If the key given by theInfo
is not in the latexStateReducerDict
, projection of the arguments to LatexState
is returned. In the case at hand, theInfo
has fields name = "section"
and typ = "macro"
, and the function returned by the dictionary is SRH.updateSectionNumber x y
. Here SRH
is an alias of the StateReducerHelper
module. Referring to that module, we find that
Thus updateSectionNumber
increments the "s1" counter in the latexState
and sets the other section counters to zero. The addSection
function, listed below, adds the current section to the table of contents field of the LatexState
:
We will not go down the rabbit hole any further, but you get the general idea. The LatexState
holds counters, the table of contents, cross references, and a general-purpose dictionaray. To add new abilities to MiniLatex
, one can add new entries to latexStateReducerDict
or new fields to LatexState
.
Example: rendering a section
To conclude this discussion, we exhibit the render for sections: s
Appendix: the latexStateReducerDict
Some conclusions
The reliance of Accumulator.parse
and Accumulator.render
on the LatexState
record, as well as the latexStateReducerDict
for dispatching calls to latexStateReducer
, makes it very easy to add new features, e.g., new macros and environments whose rendering requires a computed state. Moreover, it is not hard to add fields to LatexState
in order to add further new features. Indeed, the first version of LatexInfo
had only a counters
field. Others were added later as the scope of MiniLatex grew.
Last updated