我使用准引号在编译时创建我的智能构造数据类型.这看起来像:
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 |]
(如果需要,我可以提供一个独立的工作示例 – 我只是从更大的代码库中提取这个示例)
基本上,通过为我的newtypes导出Lift,我可以将数据类型放在表达式准引号[| txt |]实现quoteExp.
但是我在使用quotePat时遇到了麻烦.如果我这样做:
Just txt -> [p| txt |]
然后我得到一个警告,第一个txt未使用,第二个阴影第一个.我很确定那个模式只是创建一个新的名称txt,而不是像范式指针那样拼接范围内的txt,因为当我这样做时:
f :: NonEmptyText -> Bool
f [compileNonEmptyText|test|] = True
f _ = False
一切都与第一个陈述相符.
最佳答案 好吧,我想我已经明白了.从基本字符串s开始,我可以将它包装在StringL和LitP中以获取文字字符串,因为Text的IsString实例将成为Text.从那里我需要使用ConP应用NonEmptyText构造函数:
compileNonEmptyTextPattern' :: String -> Q TH.Pat
compileNonEmptyTextPattern' s = case mkNonEmptyText (pack s) of
Nothing -> fail $"Invalid NonEmptyText: " ++ s
Just (NonEmptyText txt) -> pure $ConP 'NonEmptyText [(LitP (StringL (T.unpack txt)))]
不幸的是,这比表达版本更冗长!我想知道是否可以为Q Pat提供一个类型类,例如Lift适用于Q Exp?