Рассмотрим этот файл на Haskell:
{-# 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 ()
Он использует Template Haskell для определения обязательств по тестированию, которые тестируются плагином GHC при инспекционном тестировании.
Под капотом инспекционное тестирование передает имя Template Haskell в аннотации и преобразует его в имя Core, используя thNameToGhcName
, а затем пытается найти это имя в текущем модуле.
Это прекрасно работает, если я создаю шаблон имени Хаскелла, используя 'foo
, но не работает, если я использую lookupValueName
.
- Почему они разные?
- Как я могу воссоздать поведение
'foo
, когда у меня есть строка?
(Почему я не просто использую 'foo
? Потому что я хочу динамически создавать обязательства, поэтому у меня есть код Template Haskell, который определяет множество таких функций и обязательств.)