Я использую квази-кавычки для создания своих умно сконструированных типов данных во время компиляции.Это выглядит примерно так:
import qualified Data.Text as T
import Language.Haskell.TH.Quote (QuasiQuoter(..))
import Language.Haskell.TH (Q, Exp, Pat(..), Lit(..))
import Language.Haskell.TH.Syntax (Lift(..))
import qualified Language.Haskell.TH.Syntax as TH
import Instances.TH.Lift () -- th-lift-instances package
newtype NonEmptyText = NonEmptyText Text
textIsWhitespace :: Text -> Bool
textIsWhitespace = T.all (== ' ')
mkNonEmptyText :: Text -> Maybe NonEmptyText
mkNonEmptyText t = if textIsWhitespace t then Nothing else (Just (NonEmptyText t))
compileNonEmptyText :: QuasiQuoter
compileNonEmptyText = QuasiQuoter
{ quoteExp = compileNonEmptyText'
, quotePat = error "NonEmptyText is not supported as a pattern"
, quoteDec = error "NonEmptyText is not supported at top-level"
, quoteType = error "NonEmptyText is not supported as a type"
}
where
compileNonEmptyText' :: String -> Q Exp
compileNonEmptyText' s = case mkNonEmptyText (pack s) of
Nothing -> fail $ "Invalid NonEmptyText: " ++ s
Just txt -> [| txt |]
(я могу предоставить автономный рабочий пример, если необходимо - я только что вытащил этот пример из большой кодовой базы)
По сути, просто выводя Lift
для моих новых типов я могу поместить тип данных в выражение квази-кавычку [| txt |]
для реализации quoteExp
.
Но у меня возникли проблемы с quotePat
.Если я сделаю, например:
Just txt -> [p| txt |]
Тогда я получу предупреждение, что первый текст не используется, а второй затеняет первый.Я почти уверен, что этот шаблон просто создает новое имя txt
, а не встраивает в область действия txt
, как это сделал выражение квази-квотер, поскольку, когда я делаю:
f :: NonEmptyText -> Bool
f [compileNonEmptyText|test|] = True
f _ = False
всесоответствует первому утверждению.