问题
Consider this Haskell file:
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_GHC -fplugin Test.Inspection.Plugin #-}
module Text (main) where
import Test.Inspection
import Data.Text as T
import Data.Text.Encoding as E
import Data.ByteString (ByteString)
import Language.Haskell.TH
toUpperString :: String -> String
toUpperString = T.unpack . T.toUpper . T.pack
toUpperBytestring :: ByteString -> String
toUpperBytestring = T.unpack . T.toUpper . E.decodeUtf8
do Just n <- lookupValueName "toUpperString"
inspect $ n `hasNoType` ''T.Text
inspect $ 'toUpperBytestring `hasNoType` ''T.Text
main :: IO ()
main = return ()
It uses Template Haskell to define test obligations which are tested by the GHC plugin in inspection-testing.
Under the hood, inspection testing passes a Template Haskell name in an annotation, and converts it to to a Core name using thNameToGhcName
, and then tries to find this name in the current module.
This works fine if I create a template Haskell name using 'foo
, but it fails if I use lookupValueName
.
- Why are they different?
- How can I recreate the behavior of
'foo
when I have a string?
(Why do I not just use 'foo
? Because I want to dynamically create obligations, so I have Template Haskell code that defines many such functions and obligations.)
回答1:
The problem in this case is not so much that the Name
returned by 'foo
vs. lookupValueName
is different, but that using 'foo
keeps foo
alive throughout the compilation of the module, while lookupValueName "foo"
does not. Then GHC removes the binding of "foo"
and inspection-testing trips over it.
And indeed removing the export list from the module, which keeps all top-level bindings around, makes the problem go away.
来源:https://stackoverflow.com/questions/50236926/how-to-replicate-the-behaviour-of-name-in-a-th-splice