Now that we're on GHC 8.6, we can use `-XDerivingVia` in many cases
where we previously had to write instances by hand. If you're not
familiar with `-XDerivingVia`, the [GHC proposal][ghc] is a good place
to start.
[ghc]: https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0023-deriving-via.rst
Thanks to the `generic-monoid` package, we can derive a `Semigroup`
instance for any product type whose members are `Semigroups`, and the
same goes for `Monoid`. This entails an extra dependency, but it is
better than the `generic-deriving` package, which is way too much overhead.
I've also switched some trivial definitions to newtype-deriving.
Please be aware that this bumps `hlint` and `haskell-src-exts` so that
`hlint` doesn't choke on the `DerivingVia` extension. You'll need to
`stack install hlint` to get it on your `PATH`. Apologies!
Bumps most of our dependencies.
Code changes:
* algebraic-graphs-0.3 no longer provides a Foldable or Traversable
implementation for `Graph`, so now neither does our `Graph` type.
* CMark parsing now uses safe rendering of raw HTML/URLs by default,
so there is no reason to pass an `optSafe` anymore.
* algebraic-graphs now no longer requires an Eq constraint on the
output type it generates, so we can ditch our Serializing.DOT
module. (Andrey fixed this for us specifically!)
Given that @tclem and I have found the matcher API frustrating, I've
taken a stab at improving its ergonomics, and I've found some success
in separating composition of matchers from predicate-based narrowing
thereof.
The biggest change here is the elimination of the old `match`
combinator, which proved to be clumsy in that it complected narrowing
and composition. Top-down matching combinators are now written with
the `need` combinator and the `>>>` combinator, which is more readable
and more versatile. Here's a matcher that accepts functions with
Python docstrings:
```haskell
docstringMatcher :: ( Decl.Function :< fs
, [] :< fs
, Lit.TextElement :< fs
, term ~ Term (Sum fs) ann
) => Matcher term term
docstringMatcher = target <*
(need Decl.functionBody
>>> narrow @[]
>>> mhead
>>> narrow @Lit.TextElement
>>> ensure Lit.isTripleQuoted))
```
Pretty readable, right? Each step of the tree regular expression -
choosing function bodies, ensuring said bodies are lists, examining
the first element, and choosing only TextElements containing
triple-quoted strings - is made implicit. The old way would have
looked something like this:
```haskell
docstringMatcher = target <* match Decl.functionBody
$ narrow
$ matchM listToMaybe
$ target <* ensure Lit.isTripleQuoted
```
which is a good deal more disorganized and less flexible
in the quite-common case of applying functions during a
matching pass. Separating the act of composition from
function application is a big win here.
Further comments are inline.