Add more high-level documentation: index, dataflow
parent
eac73c9a7b
commit
d56c4f5e6b
|
@ -103,7 +103,6 @@ stack build
|
||||||
- -XBangPatterns
|
- -XBangPatterns
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
# Implementation
|
# Implementation/High-level Documentation
|
||||||
|
|
||||||
I have started adding documentation about the main data type `BriDoc`; see the
|
[See the documentation index](docs/implementation/index.md)
|
||||||
"docs/implementation" folder. Start with "bridoc-design.md".
|
|
||||||
|
|
|
@ -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`
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -9,8 +9,9 @@ project, including the following two:
|
||||||
|
|
||||||
These two goals stand in conflict, and this project chooses a solution
|
These two goals stand in conflict, and this project chooses a solution
|
||||||
to this that distinguishes it from (all) other existing formatters. This
|
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
|
approach was an important motivation for writing Brittany, when other
|
||||||
even be applicable to more general-purposes structured-document formatters
|
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
|
(although we will not expand on that here). Before explaining the idea, we
|
||||||
will first consider
|
will first consider
|
||||||
|
|
||||||
|
@ -55,8 +56,8 @@ same expression:
|
||||||
|
|
||||||
~~~~.hs
|
~~~~.hs
|
||||||
-- 10 20 30 40
|
-- 10 20 30 40
|
||||||
-- 1) -- | lets assume the user wants
|
-- 1) -- lets assume the user wants
|
||||||
nestedCaseExpr = case e1 of -- | 40 columns max.
|
nestedCaseExpr = case e1 of -- 40 columns max.
|
||||||
Left x -> if func x then "good" else "bad" -- too long
|
Left x -> if func x then "good" else "bad" -- too long
|
||||||
-- 2) --
|
-- 2) --
|
||||||
nestedCaseExpr = case e1 of --
|
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
|
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
|
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
|
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
|
not have a total order because we cannot generally prefer one of two spacings
|
||||||
where the first uses more columns, the second more lines.
|
where the first uses more columns, the second more lines.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue