Announcing template-haskell-lift and template-haskell-quasiquoter

Posted on by Teo Camarasu

IntroductionπŸ”—

The template-haskell package has a large interface, which includes both stable and unstable parts. The unstable part changes with almost every new version of GHC. This introduces extra work for users of the library who only rely on the stable parts. They now have to update their upper bounds to accommodate the new major version in order to use a new version of GHC.

I’m happy to announce the first release of two libraries that expose stable subsets of the template-haskell interface:

  • template-haskell-lift: a stable home for the Lift typeclasss.
  • template-haskell-quasiquoter: a stable home for the QuasiQuoter type.

These implement GHC Proposal 696.

By replacing a dependency on template-haskell with one or both of these libraries, users will be more insulated from breaking changes.

These smaller interfaces are much less likely to change going forward. If they do change, we will try to release versions that are compatible with multiple major versions of GHC to ease the transition.

In some cases, these smaller libraries also allow us to backport new features to older versions of GHC. For instance, GHC-9.16’s template-haskell library will ship with a new defaultQuasiQuoter utility, but if you use template-haskell-quasiquoter you will be able to benefit from this immediately.

Using template-haskell-liftπŸ”—

Suppose you have a module that defines a datatype Foo and you want to add a Lift typeclass instance.

You should add template-haskell-lift to your .cabal file’s build-depends section and then you can derive a Lift instance like so:

{-# LANGUAGE DeriveLift #-}
module Foo
import Language.Haskell.TH.Lift (Lift)

data Foo = ...
  deriving Lift

If you need to write a custom instance, I would recommend using (Typed) Template Haskell splices, rather than using the TemplateHaskell AST types directly from template-haskell. template-haskell-lift provides compatibility shims for lifting some types that lack appropriate Lift instances.

Using template-haskell-quasiquoterπŸ”—

Similarly for QuasiQuoters, users can add template-haskell-quasiquoter to their build-depends and then use it like so:

module FooQuasi
import Foo
import Language.Haskell.TH.QuasiQuoter (QuasiQuoter(..), namedDefaultQuasiQuoter)
import Language.Haskell.TH.Lift (lift)

fooQQ :: QuasiQuoter
fooQQ = namedDefaultQuasiQuoter "fooQQ" {quoteExp = \str -> lift . read @Foo}

ConclusionπŸ”—

These libraries should help make it easier to upgrade to a new version of GHC. The more people use them, the greater the benefits will be, so I encourage folks to start using them in their own libraries.

For more information about plans to improve the stability of Template Haskell, take a look at my HEW 2025 talk. For more information about the design of these libraries take a look at GHC Proposal 696.

If you encounter any issues or have suggestions, please open an issue on the respective issue tracker: