Search code examples
haskelluniplate

Deriving Uniplate with Derive


My program is using Uniplate.Data extensively, and want to improve its performance.

Currently I'm deriving Data instances automatically using the DeriveDataTypeable GHC extension.

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Data
import Data.Generics.Uniplate.Data

data Expr = Val Int
          | Neg Expr
          | Add Expr Expr
  deriving (Data,Typeable)

The Uniplate.Data package description recommend using Uniplate.Direct because of superior performance. The latter requires writing explicit Uniplate instances for data types, and recommend the Derive tool for that.

When trying to derive instances automatically using Derive:

{-# LANGUAGE TemplateHaskell #-}
import Data.DeriveTH
import Data.Generics.Uniplate.Direct

data Expr = Val Int
          | Neg Expr
          | Add Expr Expr

$( derive makeUniplateDirect ''Expr )

I get the following error:

Exception when trying to run compile-time code:
  Derivation of UniplateDirect does not yet support Template Haskell, requires info for Expr
Code: derive makeUniplateDirect ''Expr

Is there any other way of deriving Uniplate.Direct instances automatically?

Thanks!


Solution

  • As the error message says, UniplateDirect doesn't support TH mode of derive, so you have to use the standalone executable version as a preprocessor to generate the Uniplate instance.

    You can do this by adding {-! !-} directives, and setting derive as a preprocessor to be run by GHC:

    {-# OPTIONS_GHC -F -pgmFderive -optF-F #-}
    import Data.Generics.Uniplate.Direct
    
    data Expr = Val Int
              | Neg Expr
              | Add Expr Expr
    
    {-!
    deriving instance UniplateDirect Expr
    !-}
    

    Loading this into GHCi for a quick test confirms you have your instance:

    [1 of 1] Compiling Main             ( SO31725183.hs, interpreted )
    Ok, modules loaded: Main.
    *Main> :i Expr
    data Expr = Val Int | Neg Expr | Add Expr Expr
            -- Defined at D:\cygwin\tmp\ghc13224_0\ghc13224_3.hspp:6:1
    instance Uniplate Expr
      -- Defined at D:\cygwin\tmp\ghc13224_0\ghc13224_3.hspp:16:10