模板 Haskell 和 Quasiquotes 的語法

模板 Haskell 由 -XTemplateHaskell GHC 擴充套件啟用。此擴充套件啟用了本節中進一步詳述的所有語法功能。有關 Template Haskell 的完整詳細資訊,請參見使用者指南

接頭

  • splice 是一個由 Template Haskell 啟用的新語法實體,寫為 $(...),其中 (...) 是一個表示式。

  • $ 和表示式的第一個字元之間不能有空格; 和模板 Haskell 覆蓋了 $ 運算子的解析 - 例如,f$g 通常被解析為 ($) f g,而啟用了 Template Haskell,它被解析為拼接。

  • 當拼接出現在頂層時,可以省略 $。在這種情況下,拼接表示式是整行。

  • splice 表示在編譯時執行以生成 Haskell AST 的程式碼,並且該 AST 被編譯為 Haskell 程式碼並插入到程式中

  • 拼接可以代替:表示式,模式,型別和頂級宣告。在每種情況下,拼接表達的型別分別是 Q ExpQ PatQ TypeQ [Decl]。請注意,宣告拼接可能出現在頂層,而其他拼接可能分別出現在其他表示式,模式或型別中。

表示式引用(注意: 不是 QuasiQuotation)

  • 表示式引用是一個新的語法實體,寫成以下之一:

    • [e|..|][|..|] - .. 是一個表示式,引用的型別為 Q Exp;
    • [p|..|] - .. 是一種模式,引用的型別為 Q Pat;
    • [t|..|] - .. 是一個型別,引用的型別為 Q Type;
    • [d|..|] - .. 是一個宣告列表,引用的型別為 Q [Dec]
  • 表示式引用採用編譯時程式並生成該程式表示的 AST。

  • 在沒有拼接的情況下在引用中使用值(例如\x -> [| x |])對應於\x -> [| $(lift x) |] 的語法糖,其中 lift::Lift t => t -> Q Exp 來自類

    class Lift t where
      lift::t -> Q Exp
      default lift::Data t => t -> Q Exp

鍵入的拼接和引用

  • 型別拼接與之前提到的(無型別)拼接類似,並且寫為 $$(..),其中 (..) 是表示式。

  • 如果 e 的型別為 Q (TExp a),則 $$e 的型別為 a

  • 輸入的引文采用 [||..||] 的形式,其中 ..a 型別的表示式; 結果引號的型別為 Q (TExp a)

  • 鍵入的表示式可以轉換為無型別的表示式:unType::TExp a -> Exp

QuasiQuotes

  • QuasiQuotes 概括了表示式引用 - 之前,表示式引用使用的解析器是固定集(e,p,t,d)之一,但 QuasiQuotes 允許定義自定義解析器並在編譯時使用它來生成程式碼。準引用可以出現在與常規引用相同的上下文中。

  • 準引用被寫為 [iden|...|],其中 idenLanguage.Haskell.TH.Quote.QuasiQuoter 型別的識別符號。

  • QuasiQuoter 簡單地由四個解析器組成,每個解析器可以出現一個不同的上下文:

    data QuasiQuoter = QuasiQuoter { quoteExp  :: String -> Q Exp,
                                     quotePat  :: String -> Q Pat,
                                     quoteType::String -> Q Type,
                                     quoteDec  :: String -> Q [Dec] }

名稱

  • Haskell 識別符號由 Language.Haskell.TH.Syntax.Name 型別表示。名稱形成抽象語法樹的葉子,表示模板 Haskell 中的 Haskell 程式。

  • 當前在範圍內的識別符號可以變為具有以下任一名稱的名稱:'e'T。在第一種情況下,e 在表示式範圍內被解釋,而在第二種情況下,T 在型別範圍內(回想一下型別和值建構函式可以在 Haskell 中沒有歧義地共享名稱)。