wiki:Commentary/Compiler/GenericDeriving

Version 33 (modified by dreixel, 3 years ago) (diff)

--

The new Generic Deriving mechanism (ongoing work)

GHC includes a new (in 2010) mechanism to let you write generic functions. It is described in A generic deriving mechanism for Haskell, by Magalhães, Dijkstra, Jeuring and Löh. This page sketches the specifics of the implementation; we assume you have read the paper.

This mechanism replaces the previous generic classes implementation. The code is in the ghc-generics branch of the ghc, base, ghc-prim, and testsuite repos.

Changes from the paper

In the paper we describe the implementation in UHC. The implementation in GHC is slightly different:

  • We are using type families, so the Representable0 and Representable1 type classes have only one type argument. So, in GHC the classes look like what we describe in "Avoiding extensions" part of Section 2.3 of the paper. This change affects only a generic function writer, and not a generic function user.
  • Default definitions (Section 3.3) work differently. In GHC we don't use a DERIVABLE pragma; instead, a type class can declare a generic default method, which is akin to a standard default method, but includes a generic type signature. For example, the Encode class of Section 3.1 is now:
    class Encode a where
      encode :: a -> [Bit]
      default encode :: (Representable0 a, Encode1 (Rep a)) => a -> [Bit]
      encode = encode1 . from0
    
    This removes the need for a separate default definition and a pragma.
  • To derive generic functionality to a user type, the user no longer uses deriving instance (Section 4.6.1). Instead, the user gives an instance without defining the method; GHC then uses the generic default. For instance:
    instance Encode [a] -- works if there is an instance Representable0 [a]
    

Main components

  • TcDeriv.tcDeriving generates an InstInfo for each data type that fulfills the isRep0 predicate. This InstInfo is the Generic instance for that type, allowing it to be handled generically (by kind-* generic functions).
  • The representation types and core functionality of the library live on GHC.Generics (on the ghc-prim package).
  • Many names have been added as known in prelude/PrelNames
  • Most of the code generation is handled by types/Generics

What already works

  • Generic instances can be derived when -XDeriveGeneric is enabled.
  • The default keyword can used for generic default method signatures when -XDefaultSignatures is enabled.
  • Generic defaults are properly instantiated when giving an instance without defining the generic default method.
  • Base types like [], Maybe, tuples, come with Generic instances.

To do

  • Generate Generic1 instances
  • Print also the Rep type instance when -ddump-deriving is on
  • Give better error messages when we cannot derive Generic (currently we say only Cannot derive Generic)
  • Register the DeriveGeneric and DefaultSignatures extensions with Cabal.
  • Do we want Show, etc. instances for types like U1, :+:, ...?

Testing

  • Tests are available under the generics directory of the testsuite.