Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't find inerface-file declaration for variable

I'm trying to shift execution of some code to compile time with GHC 8 and template-haskel-2.11. The code looks like this:

myThHelper :: FilePath -> Q Exp
myThHelper path =
  runIO (compileThatFile path) >>= liftData

This is a simplified version of that code but it hopefully conveys what I'm trying to do.

Note the liftData function, it's new in template-haskell-2.11 and it promises to “lift” into expression any instance of Data. Very cool and it compiles.

However, when I use it like so:

main :: IO ()
main = do
  let compiled = $(myThHelper "/path/to/my/file/foo.txt")
  …

I'm getting the following error message from the compiler:

• Can't find interface-file declaration for variable Data.Text.Internal.pack
    Probable cause: bug in .hi-boot file, or inconsistent .hi file
    Use -ddump-if-trace to get an idea of which file caused the error
• In the first argument of ‘PName’, namely
    ‘Data.Text.Internal.pack ((:) 'f' ((:) 'o' ((:) 'o' [])))’
  In the first argument of ‘Template’, namely
    ‘PName (Data.Text.Internal.pack ((:) 'f' ((:) 'o' ((:) 'o' []))))’
  In the expression:

etc. Any idea what's going on and how to fix it?


I confirmed via experiments that the problem only manifests itself when data type to lift has Text in it. I'm going to open an issue.


And here it is.

like image 308
Mark Karpov Avatar asked Jul 01 '16 10:07

Mark Karpov


1 Answers

This seems to be because dataToQa expects the function that toConstr shows (which is "pack" for Text) to be in the same module the data type is defined. So liftData is looking for pack in Data.Text.Internal but pack is actually in Data.Text.

An easy way to fix it is to just write your own lift function for Text:

{-# LANGUAGE TemplateHaskell #-}

import qualified Data.Text as T
import Language.Haskell.TH.Syntax

liftText :: T.Text -> Q Exp
liftText txt = AppE (VarE 'T.pack) <$> lift (T.unpack txt)

myThHelper :: FilePath -> Q Exp
myThHelper path =
  runIO (compileThatFile path) >>= liftText

If text is deep in the structure you want to use, you can use dataToExpQ which lets you override the lift function for type-specific cases:

import Data.Data

liftDataWithText :: Data a => a -> Q Exp
liftDataWithText = dataToExpQ (\a -> liftText <$> cast a)
like image 137
cchalmers Avatar answered Nov 18 '22 15:11

cchalmers