【问题标题】:How can I write a pattern quasi quoter in Haskell?如何在 Haskell 中编写模式准引用器?
【发布时间】:2019-07-14 20:20:56
【问题描述】:

我使用准引用器在编译时创建我的智能构造数据类型。这看起来像:

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,而不是像准引用器那样在范围内拼接txt,因为当我这样做时:

f :: NonEmptyText -> Bool
f [compileNonEmptyText|test|] = True
f _ = False

一切都与第一个语句匹配。

【问题讨论】:

    标签: haskell template-haskell quasiquotes


    【解决方案1】:

    好吧,我想我明白了。从基本字符串s 开始,我可以将其包装在StringLLitP 中以获得文字字符串,因为TextIsString 实例将变为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 是否有一个类型类,比如LiftQ Exp

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多