On Wed, May 13, 2015 at 6:13 AM, Merijn Verstraaten <merijn@inconsistent.nl> wrote:
>
> Is there any reason we can't have GHC derive Lift instance automatically? I know there's already a TH library for this, but I guess I don't see why GHC can't derive them for us. Additionally, the lack of lift instances is really a pain for a lot of compile time evaluation tricks.

There are two libraries to get your orphan Lift instances: th-orphans and th-lift-instances.

Here's a list of what should be all the Lift instances on hackage: <http://code.haskell.org/~aavogt/lift_instances_hackage.txt>. There are many duplicates. Text and Double instances happen quite often (9 in ~ 715 packages depending on template-haskell):

Text (Lazy or Strict)
  ./aeson-schema-0.3.0.5/src/Data/Aeson/TH/Lift.hs
  ./parse-help-0.0/System/Console/ParseHelp.hs
  ./ssh-0.3.1/test/EmbedTree.hs
  ./SimpleLog-0.1.0.3/src/System/Log/SLog/Format.hs
  ./persistent-template-2.1.3/Database/Persist/TH.hs -- indirectly via a Lift' class
  ./th-lift-instances-0.1.5/src/Instances/TH/Lift.hs
  ./typedquery-0.1.0.2/src/Database/TypedQuery/Types.hs
  ./haskhol-core-1.1.0/src/HaskHOL/Core/Kernel/Prims.hs
  ./lighttpd-conf-0.4/src/Lighttpd/Conf/Instances/Lift.hs
  ./yaml-rpc-1.0.3/Network/YAML/API.hs

Double
  ./aeson-schema-0.3.0.5/src/Data/Aeson/TH/Lift.hs
  ./th-orphans-0.11.1/src/Language/Haskell/TH/Instances.hs
  ./paragon-0.1.28/src/Language/Java/Paragon/QuasiQuoter/Lift.hs
  ./ta-0.1/Database/TA/Helper/LiftQ.hs
  ./CCA-0.1.5.3/src/Language/Haskell/TH/Instances.hs
  ./th-lift-instances-0.1.5/src/Instances/TH/Lift.hs
  ./llvm-general-quote-0.2.0.0/src/LLVM/General/Quote/AST.hs
  ./Eq-1.1.3/Language/Eq/Quasiquote.hs
  ./ivory-0.1.0.0/src/Ivory/Language/Syntax/AST.hs


Those orphans could be removed if we had instance Data a => Lift a, because those types have a mostly sane Data instance. While there are some differences in the Double instances:

lift x = [| read $(lift (show x)) |] -- in ./paragon-0.1.28/src/Language/Java/Paragon/QuasiQuoter/Lift.hs

lift d = [| D# $(return (LitE (DoublePrimL (toRational d)))) |]

lift d = [| fromRational $(litE . rationalL . toRational $ d) :: Double |]

lift = lift . toRational

$(lift (0/0)) is wrong for most instances already: going through Rational gives -Infinity. Incidentally dataToExpQ (const Nothing) (0/0) also gives -Infinity.

Another difference is whether :t $(lift (1.0 :: Double)) is Double, Fractional a => a, Read a => a, or something else.

Apart from those two issues, it seems that the duplicated Lift instances do the same thing as liftData, so the "adding an import will change the program's runtime behavior" seems rare compared with "adding an import breaks your program because we didn't agree to put the orphans in one package only".

So I'm:

+1 on Data a => Lift a
+1 on the DefaultSignatures, if the overlapping instance won't happen