| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Data.ZipMatchK.TH
Description
Template Haskell derivation of ZipMatchK instances.
The generic instance (the one you get by writing instance ZipMatchK TermSig
with no body) converts a node into its Generics.Kind representation on
every comparison, and converts the result back. The representation of a
constructor is a chain of L1/R1 wrappers as long as that constructor's
index, so the cost grows with the number of constructors in the signature,
and comparing terms is most of what a typechecker does.
The derivers here generate the instance that one would otherwise write out by
hand: a case over the two nodes, allocating only its result. On a
44-constructor signature that is worth a factor of 1.8 in time and 2.3 in
allocation on alphaEquiv (see the zipmatchk
benchmark), and the derived instance does not get slower as the signature
grows.
The module the splice appears in needs at least
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}Signatures that refer to one another — as the ones generated by
mkFreeFoil from a grammar with
several syntactic categories do — have to be derived in a single splice,
since a top-level splice ends a declaration group and an instance from a later
group is not visible to an earlier one:
concat <$> traverse deriveZipMatchK2 [''Term'Sig, ''OpArg'Sig, ''Type'Sig]
Synopsis
- deriveZipMatchK :: Name -> Q [Dec]
- deriveZipMatchK1 :: Name -> Q [Dec]
- deriveZipMatchK2 :: Name -> Q [Dec]
- deriveZipMatchKWith :: Maybe Int -> Name -> Q [Dec]
Documentation
deriveZipMatchK :: Name -> Q [Dec] Source #
Derive a ZipMatchK instance, zipping all type parameters.
For a signature bifunctor
data TermSig scope term = AppSig term term | LamSig scope deriveZipMatchK ''TermSig
this generates
instance ZipMatchK TermSig where
zipMatchWithK (f :^: g :^: M0) x y = case (x, y) of
(AppSig l1 l2, AppSig r1 r2) -> AppSig <$> g l1 r1 <*> g l2 r2
(LamSig l1, LamSig r1) -> LamSig <$> f l1 r1
_ -> NothingUse deriveZipMatchK2 when the type has extra parameters that should stay
fixed (an annotation, say), as a signature generated by
Control.Monad.Free.Foil.TH.MkFreeFoil does.
deriveZipMatchK1 :: Name -> Q [Dec] Source #
Derive a ZipMatchK instance for a functor, zipping the last type parameter
and fixing the rest.
deriveZipMatchK2 :: Name -> Q [Dec] Source #
Derive a ZipMatchK instance for a signature bifunctor, zipping the last two
type parameters (the scoped terms and the terms) and fixing the rest.
For a signature with an extra parameter (a source position, for instance)
data Term'Sig a scope term = AppSig a term term | LamSig a scope deriveZipMatchK2 ''Term'Sig
this generates
instance ZipMatchK a => ZipMatchK (Term'Sig a) where
zipMatchWithK (f :^: g :^: M0) x y = case (x, y) of
(AppSig l1 l2 l3, AppSig r1 r2 r3) ->
AppSig <$> zipMatchWithK M0 l1 r1 <*> g l2 r2 <*> g l3 r3
...