th-desugar Package

This package provides the Language.Haskell.TH.Desugar module, which desugars
Template Haskell’s rich encoding of Haskell syntax into a simpler encoding.
This desugaring discards surface syntax information (such as the use of infix
operators) but retains the original meaning of the TH code. The intended use
of this package is as a preprocessor for more advanced code manipulation
tools. Note that the input to any of the ds... functions should be produced
from a TH quote, using the syntax [| ... |]. If the input to these functions
is a hand-coded TH syntax tree, the results may be unpredictable. In
particular, it is likely that promoted datatypes will not work as expected.

One explicit goal of this package is to reduce the burden of supporting multiple
GHC / TH versions. Thus, the desugared language is the same across all GHC versions,
and any inconsistencies are handled internally.

The package was designed for use with the singletons package, so some design
decisions are based on that use case, when more than one design choice was
possible.

I will try to keep this package up-to-date with respect to changes in GHC.

Changes

th-desugar release notes

Version 1.9

Suppose GHC 8.6.

Add support for DerivingVia. Correspondingly, there is now a
DDerivStrategy data type.

Add support for QuantifiedConstraints. Correspondingly, there is now a
DForallPr constructor in DPred to represent quantified constraint types.

Remove the DStarT constructor of DType in favor of DConT ''Type.
Two utility functions have been added to Language.Haskell.TH.Desugar to
ease this transition:

isTypeKindName: returns True if the argument Name is that
of Type or ★ (or *, to support older GHCs).

typeKindName: the name of Type (on GHC 8.0 or later) or * (on older
GHCs).

th-desugar now desugars all data types to GADT syntax. The most significant
API-facing changes resulting from this new design are:

The DDataD, DDataFamilyD, and DDataFamInstD constructors of DDec
now have Maybe DKind fields that either have Just an explicit return
kind (e.g., the k -> Type -> Type in data Foo :: k -> Type -> Type)
or Nothing (if lacking an explicit return kind).

The DCon constructor previously had a field of type Maybe DType, since
there was a possibility it could be a GADT (with an explicit return type)
or non-GADT (without an explicit return type) constructor. Since all data
types are desugared to GADTs now, this field has been changed to be simply
a DType.

The type signature of dsCon was previously:

dsCon :: DsMonad q => Con -> q [DCon]

However, desugaring constructors now needs more information than before,
since GADT constructors have richer type signatures. Accordingly, the type
of dsCon is now:

The instance Desugar [Con] [DCon] has also been removed, as the previous
implementation of desugar (concatMapM dsCon) no longer has enough
information to work.

Some other utility functions have also been added as part of this change:

A conExistentialTvbs function has been introduced to determine the
existentially quantified type variables of a DCon. Note that this
function is not 100% accurate—refer to the documentation for
conExistentialTvbs for more information.

A mkExtraDKindBinders function has been introduced to turn a data type’s
return kind into explicit, fresh type variable binders.

A toposortTyVarsOf function, which finds the free variables of a list of
DTypes and returns them in a well scoped list that has been sorted in
reverse topological order.

th-desugar now desugars partial pattern matches in do-notation and
list/monad comprehensions to the appropriate invocation of fail.
(Previously, these were incorrectly desugared into case expressions with
incomplete patterns.)

Add a mkDLamEFromDPats function for constructing a DLamE expression using
a list of DPat arguments and a DExp body.

Add an unravel function for decomposing a function type into its forall’d
type variables, its context, its argument types, and its result type.

Export a substTyVarBndrs function from Language.Haskell.TH.Desugar.Subst,
which substitutes over type variable binders in a capture-avoiding fashion.

getDataD, dataConNameToDataName, and dataConNameToCon from
Language.Haskell.TH.Desugar.Reify now look up local declarations. As a
result, the contexts in their type signatures have been strengthened from
Quasi to DsMonad.

Export a dTyVarBndrToDType function which converts a DTyVarBndr to a
DType, which preserves its kind.

Previously, th-desugar would silently accept illegal uses of record
construction with fields that did not belong to the constructor, such as
Identity { notAField = "wat" }. This is now an error.

Version 1.8

Support GHC 8.4.

substTy now properly substitutes into kind signatures.

Expose fvDType, which computes the free variables of a DType.

Incorporate a DDeclaredInfix field into DNormalC to indicate if it is
a constructor that was declared infix.

Implement lookupValueNameWithLocals, lookupTypeNameWithLocals,
mkDataNameWithLocals, and mkTypeNameWithLocals, counterparts to
lookupValueName, lookupTypeName, mkDataName, and mkTypeName which
have access to local Template Haskell declarations.

Implement reifyNameSpace to determine a Name’s NameSpace.

Export reifyFixityWithLocals from Language.Haskell.TH.Desugar.

Export matchTy (among other goodies) from new module Language.Haskell.TH.Subst.
This function matches a type template against a target.

Version 1.7

Support for TH’s support for TypeApplications, thanks to @RyanGlScott.

Support for unboxed sums, thanks to @RyanGlScott.

Support for COMPLETE pragmas.

getRecordSelectors now requires a list of DCons as an argument. This
makes it easier to return correct record selector bindings in the event that
a record selector appears in multiple constructors. (See
goldfirere/singletons#180
for an example of where the old behavior of getRecordSelectors went wrong.)

Better type family expansion (expanding an open type family with variables works now).

Version 1.6

Work with GHC 8, with thanks to @christiaanb for getting this change going.
This means that several core datatypes have changed: partcularly, we now have
DTypeFamilyHead and fixities are now reified separately from other things.

DKind is merged with DType.

Generic instances for everything.

Version 1.5.5

Fix issue #34. This means that desugaring (twice) is idempotent over
expressions, after the second time. That is, if you desugar an expression,
sweeten it, desugar again, sweeten again, and then desugar a third time, you
get the same result as when you desugared the second time. (The extra
round-trip is necessary there to make the output smaller in certain common
cases.)

Version 1.5.4.1

Version 1.5.4

Version 1.5.3

Version 1.5.2

Version 1.5.1

Thanks to David Fox (@ddssff), sweetening now tries to use more of TH’s Type
constructors.

Also thanks to David Fox, depend usefully on the th-orphans package.

Version 1.5

There is now a facility to register a list of Dec that internal reification
should use when necessary. This avoids the user needing to break up their
definition across different top-level splices. See withLocalDeclarations.
This has a side effect of changing the Quasi typeclass constraint on many
functions to be the new DsMonad constraint. Happily, there are DsMonad
instances for Q and IO, the two normal inhabitants of Quasi.