Reputation: 654
I have a Lift
instance that works with template-haskell 2.14, but won't compile with later versions. Can someone explain what changes are needed?
{-# LANGUAGE FlexibleInstances, TemplateHaskell #-}
module LiftBS where
import Data.ByteString as B (ByteString, length, unpack)
import Data.ByteString.Unsafe (unsafePackAddressLen)
import Language.Haskell.TH (runIO, litE, stringPrimL)
import Language.Haskell.TH.Lift (Lift(lift))
instance Lift (IO B.ByteString) where
lift bsio = do
bs <- runIO bsio
[|unsafePackAddressLen $(lift (B.length bs)) $(litE (stringPrimL (B.unpack bs))) :: IO ByteString|]
Upvotes: 0
Views: 90
Reputation: 27003
That's a sketchy instance of Lift
. It's really not what Lift
is for. It isn't an accident that the new type of lift
rules out compile-time side effects. Lift
is for serializing data structures, which this isn't even doing conceptually. If this were serializing the data structure passed to it, it would be splicing in a representation of the IO action. This is executing an action and serializing the result of that action. That's just not what someone unfamiliar with this code is going to expect to happen.
Also, all the work you're putting in to serialize the ByteString
as its components hasn't been necessary since bytestring-0.11.2.0
, when it got its own Lift
instance.
But the real thing to do here is just write a function that does what you want:
atCompileTime :: Lift a => IO a -> Q Exp
atCompileTime act = do
x <- runIO act
[| pure x |]
It's not a Lift
instance, so it can have a type that allows it to do what you want. It's not a Lift
instance, so it can have a name that explains what it's actually doing. And as a bonus, it will work across a wide range of versions of template haskell.
Upvotes: 6