2.1 KiB
Dataflow
From the program design standpoint, Brittany performes a
Config -> Text -> Text
transformation; it is not interactive in any way and
it processes the whole input at once (no streaming going on). This makes for
a very simple design with nice separation of IO and non-IO.
Brittany makes heavy usage of mtl-on-steroids-style transformers, mostly limited to Reader, Writer and State. For this kind of task it makes a lot of sense; we do a pure transformation involving multiple steps that each requires certain local state during traversals of recursive data structures. By using MultiRWS we can avoid using lens for the most part without inducing too much boilerplate.
Firstly, the topmost layer, the IO bits:
The corresponding code is in these modules:
Main
Language.Haskell.Brittany
The latter contains the code to run our Reader/Writer/State stack (well, no state yet).
Note that MultiRWS
here behaves like a nicer version of a stack like
ReaderT x (ReaderT y (WriterT w1 (WriterT2 w2 (Writer w3)..)
.
The next graph zooms in on that transformation:
Two places (The BriDoc
generation and the backend) have additional local
state (added to the monadic context).
The following is a very simplified description of the BriDoc generation:
For the BriDoc
generation, the relevant modules are
Language.Haskell.Brittany.Layouters.*
Language.Haskell.Brittany.LayouterBasics
For the BriDoc
tree transformations, the relevant modules are
Language.Haskell.Brittany.Transformations.*
Finally, for the backend, the relevant modules are
Language.Haskell.Brittany.Backend
Language.Haskell.Brittany.BackendUtils