Opened 12 years ago

Closed 4 years ago

Last modified 2 years ago

#1830 closed feature request (fixed)

Automatic derivation of Lift

Reported by: guest Owned by: RyanGlScott
Priority: normal Milestone:
Component: Template Haskell Version: 6.8.1
Keywords: deriving Cc: alfonso.acosta@…, vogt.adam@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D1168
Wiki Page:


This feature request was brought up in this template-haskell thread[1]:

There are apparently two implementation alternatives:

1) Merge Ian's th-lift library[2] with the mainstream template-haskell library

2) Implement "instance Data a => Lift a" (requires allowing undecidable and overlapping instances) in template-haskell. Since Data can be derived automatically by GHC, such an instance would imply automatic derivation of Lift as well.

[1] [2]

Change History (22)

comment:1 Changed 12 years ago by igloo

difficulty: Unknown
Milestone: 6.10 branch

We should aim to decide something in time for 6.10.

comment:3 Changed 11 years ago by simonmar

Architecture: UnknownUnknown/Multiple

comment:4 Changed 11 years ago by simonmar

Operating System: UnknownUnknown/Multiple

comment:5 Changed 10 years ago by igloo

Milestone: 6.10 branch_|_

comment:6 Changed 9 years ago by aavogt

Cc: vogt.adam@… added
Type of failure: None/Unknown

comment:7 Changed 7 years ago by morabbin

Bump; worth looking at merging th-lift again?

comment:8 Changed 4 years ago by RyanGlScott

Differential Rev(s): Phab:D1168
Owner: set to RyanGlScott

I have a differential ( Phab:D1168 ) submitted which implements this feature, but I would like some feedback. I'll copy over my questions from the Phabricator page:

  1. What should we do if someone attempts to derive Lift on a datatype with no constructors? I (somewhat arbitrarily) chose it to generate code like this:
data Void deriving Lift

instance Lift Void where
    lift _ = appE (varE 'error) (litE (stringL "Void lift"))

but lift _ = error "Void lift" would also work.

  1. How should primitive data types be handled? I adapted the approach Show takes, which has special cases for Char#, Float#, Double#, Int#, and Word#. Note that template-haskell also has a StringPrimL constructor, so we could handle Addr# as well, but there's not currently a function of type String -> [Word8] in base that I could use in conjunction with it (there is in ghc, but I'm not sure if it's verboten to put GHC internals in derived code).

comment:9 Changed 4 years ago by rwbarton

What should we do if someone attempts to derive Lift on a datatype with no constructors?

Since lift then has type Void -> Q Exp, I would be inclined to define it as absurd, i.e., an empty case. I don't see the point of turning it into a runtime error when lift (error "foo") is a splice-time error for an inhabited type.

comment:10 Changed 4 years ago by goldfire

Thanks for taking this on, Ryan, but I'm unconvinced that GHC needs built-in support here. What's wrong with using th-lift? I mean, I agree that in theory, DeriveLift would be nice, but it's Yet Another Thing. If something can be done well outside of GHC, I think it should be. A common argument here is that if a feature is built-in (as opposed to requiring TH), then users don't have to use TH. But that argument falls flat here, because users are clearly already using TH!

comment:11 in reply to:  10 Changed 4 years ago by RyanGlScott

Replying to goldfire:

What's wrong with using th-lift?

Type inference. th-lift is fundamentally limited in that it cannot infer the correct instance context for complex data structures such as

data Nested f a = Nested (f a) deriving Lift

-- instance Lift (f a) => Lift (Nested f a) where ...


data R a = R a

instance (Show a, Lift a) => Lift (R a) where ...

data Restricted a = Restricted (R a) deriving Lift

-- instance (Show a, Lift a) => Lift (Restricted a) where ...

Granted, this could be improved if th-lift were changed to allow something like this:

instance (Show a, Lift a) => Lift (Restricted a) where
    lift = $(makeLift ''Restricted)

But a deriving statement is infinitely more aesthetically pleasing, in my opinion.

But that argument falls flat here, because users are clearly already using TH!

Well, they're using the template-haskell library, but not necessarily the TemplateHaskell extension. Users may want to define Lift instances for data types without actually using the TemplateHaskell extension (as doing so precludes a library from being built on a stage-1 compiler). Having access to DeriveLift allows a library to be built with Lift support on GHC stage 1 and 2, and then downstream packages that depend on the library can decide if they want to actually utilize the Lift instances by means of the TemplateHaskell extension.

comment:12 Changed 4 years ago by mpickering

Is it possible to derive these instances using GHC.Generics? Then the DeriveAnyClass extension could be used for the same syntactic effect without modifying the compiler.

comment:13 in reply to:  12 Changed 4 years ago by RyanGlScott

Replying to mpickering:

Is it possible to derive these instances using GHC.Generics?

I believe so, although with GHC.Generics you cannot have special cases for unlifted types like Int# (currently, the Phab differential uses the Lit type from template-haskell to deal with them).

comment:14 Changed 4 years ago by simonpj

I'm not dead set against this (adding new auto-derived classes doesn't interact with anything), but it does impose a little extra maintenance burden to keep it all working and you can get nearly the same behaviour with a (perhaps enhance) th-lift library.

It would seem more persuasive if there was more than one advocate for it. Is there a large constituency of TH users who will benefit from this? Data from Hackage might be illuminating... how many Lift instances exist?

comment:15 Changed 4 years ago by RyanGlScott

According to packdeps, 32 libraries immediately depend on th-lift. Doing a grep of hackage-packages for files that contain both Language.Haskell.TH.Syntax and instance Lift reveals that these additional libraries define their own Lift instances:


This obviously isn't scientifically rigorous, as there is a chance that the instance Lift could be using some other Lift, or that the Lift instances in those packages wouldn't be derivable in the first place. But this at least gives an approximation of how much impact deriving Lift might have.

comment:16 Changed 4 years ago by goldfire

Following on from Simon's comment:14, I think it would be helpful to see a discussion of -XDeriveLift on a forum/mailing list. I do see there's lots of packages that use th-lift, but perhaps these packages and their authors are quite happy continuing to do so.

I think Simon and I just want to make sure there's more than one lone ranger out there who wants this before the GHC Team commits to maintaining it into perpetuity! :) Thanks!

comment:17 Changed 4 years ago by RyanGlScott

I've started a ghc-devs mailing list thread for discussion:

comment:18 Changed 4 years ago by simonpj

See also ValidateMonoLiterals for a use-case.

comment:19 Changed 4 years ago by Austin Seipp <austin@…>

In 089b72f5/ghc:

DeriveLift extension (#1830)

This implements -XDeriveLift, which allows for automatic derivation
of the Lift class from template-haskell. The implementation is based
off of Ian Lynagh's th-lift library

Test Plan: ./validate

Reviewers: hvr, simonpj, bgamari, goldfire, austin

Reviewed By: goldfire, austin

Subscribers: osa1, thomie

Differential Revision:

GHC Trac Issues: #1830

comment:20 Changed 4 years ago by Austin Seipp <austin@…>

In 73921df/ghc:

Update Cabal to recognize DeriveLift

This should (1) fix the ./validate build, which I accidentally broke in D1168,
and (2) update the Cabal submodule so that it recognizes `DeriveLift` as a GHC

Reviewed By: adamse, austin

Differential Revision:

GHC Trac Issues: #1830

comment:21 Changed 4 years ago by jstolarek

Resolution: fixed
Status: newclosed

Phab revision is closed and the patches have been merged - I believe this ticket should also be closed.

comment:22 Changed 2 years ago by RyanGlScott

Keywords: deriving added
Note: See TracTickets for help on using tickets.