Add more high-level documentation: index, dataflow

pull/35/head
Lennart Spitzner 2017-05-11 21:39:26 +02:00
parent eac73c9a7b
commit d56c4f5e6b
4 changed files with 100 additions and 9 deletions

View File

@ -103,7 +103,6 @@ stack build
- -XBangPatterns
~~~~
# Implementation
# Implementation/High-level Documentation
I have started adding documentation about the main data type `BriDoc`; see the
"docs/implementation" folder. Start with "bridoc-design.md".
[See the documentation index](docs/implementation/index.md)

View File

@ -0,0 +1,49 @@
# 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:
<img src="https://cdn.rawgit.com/lspitzner/brittany/7775812cfdc7d2596883f87b5ba9207fbf61f2b3/doc-svg-gen/generated/periphery.svg">
The corresponding code is in these modules:
- `Main`
- `Language.Haskell.Brittany`
The latter [contains the code to run our Reader/Writer/State stack](https://github.com/lspitzner/brittany/blob/7775812cfdc7d2596883f87b5ba9207fbf61f2b3/src/Language/Haskell/Brittany.hs#L64-L75) (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:
<img src="https://cdn.rawgit.com/lspitzner/brittany/7775812cfdc7d2596883f87b5ba9207fbf61f2b3/doc-svg-gen/generated/ppm.svg">
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:
<img src="https://cdn.rawgit.com/lspitzner/brittany/7775812cfdc7d2596883f87b5ba9207fbf61f2b3/doc-svg-gen/generated/bridocgen.svg">
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`

View File

@ -0,0 +1,41 @@
- [theory](theory.md)
Explains the core idea of the formatter that makes it so cool.
- [dataflow](dataflow.md)
Looking at how the data is tranformed should give the reader a good
idea of the high-level design, given that Brittany essentially
performs a `Text -> Text` transformation.
- [bridoc-design](bridoc-design.md)
An explanation of the `BriDoc` datatype focussed on (potential) contributors
that wish to add support for more syntactical constructs.
- [bridoc-api](bridoc-api.md)
Specifying the semantics of the different (smart) constructors of the
`BriDoc` type.
- Brittany uses the following (randomly deemed noteworthy) libraries:
- [`ghc-exactprint`](https://hackage.haskell.org/package/ghc-exactprint)
(and [`ghc`](https://hackage.haskell.org/package/ghc)) for parsing of haskell source;
- [`uniplate`](https://hackage.haskell.org/package/uniplate)
for efficient transformations on the recursive `BriDoc` datatype;
this powers the main computational work done by Brittany;
- [`monad-memo`](https://hackage.haskell.org/package/monad-memo)
for explicit function memoization;
- [`multistate`](https://hackage.haskell.org/package/multistate)
as an alternative to an unwieldly transformer stack;
- [`butcher`](https://github.com/lspitzner/butcher)
for parsing commandline arguments (as an alternative to
[`optparse-applicative`](https://hackage.haskell.org/package/optparse-applicative))
- [`yaml`](https://hackage.haskell.org/package/yaml)
to handle config file;
- [`safe`](https://hackage.haskell.org/package/safe)
and
[`unsafe`](https://hackage.haskell.org/package/unsafe)
(heh).

View File

@ -9,8 +9,9 @@ project, including the following two:
These two goals stand in conflict, and this project chooses a solution
to this that distinguishes it from (all) other existing formatters. This
idea was the motivation to write Brittany in the first place, and it might
even be applicable to more general-purposes structured-document formatters
approach was an important motivation for writing Brittany, when other
formatters already existed. The approach might
also be applicable to more general-purposes structured-document formatters
(although we will not expand on that here). Before explaining the idea, we
will first consider
@ -55,8 +56,8 @@ same expression:
~~~~.hs
-- 10 20 30 40
-- 1) -- | lets assume the user wants
nestedCaseExpr = case e1 of -- | 40 columns max.
-- 1) -- lets assume the user wants
nestedCaseExpr = case e1 of -- 40 columns max.
Left x -> if func x then "good" else "bad" -- too long
-- 2) --
nestedCaseExpr = case e1 of --
@ -193,9 +194,10 @@ required per node of the input.
this to the `nestedCaseExpr` example above: The options are to either
put the right-hand-side of the case-alternative into a new line, or
split up the if-then-else. The "case" is the outer one, so Brittany will
prefer 3) over 2), which proves to be the right choice (here).
prefer 3) over 2), which proves to be the right choice (at least in this
case).
As a consequence, we are most interested in the maximum spacings; yet, we do
As a consequence, we are most interested in the maximum spacings. Still we do
not have a total order because we cannot generally prefer one of two spacings
where the first uses more columns, the second more lines.