From d56c4f5e6bca9137d173463f85741e7850cf6c49 Mon Sep 17 00:00:00 2001 From: Lennart Spitzner Date: Thu, 11 May 2017 21:39:26 +0200 Subject: [PATCH] Add more high-level documentation: index, dataflow --- README.md | 5 ++-- docs/implementation/dataflow.md | 49 +++++++++++++++++++++++++++++++++ docs/implementation/index.md | 41 +++++++++++++++++++++++++++ docs/implementation/theory.md | 14 ++++++---- 4 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 docs/implementation/dataflow.md create mode 100644 docs/implementation/index.md diff --git a/README.md b/README.md index 0b19d32..635873d 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/docs/implementation/dataflow.md b/docs/implementation/dataflow.md new file mode 100644 index 0000000..8a6c8df --- /dev/null +++ b/docs/implementation/dataflow.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: + + + +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: + + + +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` + diff --git a/docs/implementation/index.md b/docs/implementation/index.md new file mode 100644 index 0000000..f6adfad --- /dev/null +++ b/docs/implementation/index.md @@ -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). + diff --git a/docs/implementation/theory.md b/docs/implementation/theory.md index 7795a2a..7def78d 100644 --- a/docs/implementation/theory.md +++ b/docs/implementation/theory.md @@ -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.