reify
∷ Name → Q Info
returns information about the given name: if it is a global identifier (function, constant, constructor), you will get its type, if it is a type or class, you will get its structure. The Info
type definition can be found in the Language.Haskell.TH.Syntax
module. $(optimize [d| fib = … |])
fib = $(optimize [| … |])
reify
function and the type of Info
, but there are some subtleties associated, for example, with the fact that you can get information not about any name. If this topic is interesting, I can collect some information and write a separate note about it (or paste it here).∷ Name
) corresponding to the identifier of interest, you can use the mkName
function, but this is not a safe solution, because mkName
returns an mkName
name that can be interpreted differently depending on the context. But the code VarE id ← [| foo |]
VarE id ← [| foo |]
is safe in this sense, since quoting qualifies names (you get something like My.Own.Module.foo
), but this code is too verbose and requires a monadic context to use. Fortunately, Template Haskell, has another simple form of citing names: 'foo
(single quote before foo
) has type Name
and contains a qualified name corresponding to the identifier foo
, so the code let id = 'foo
equivalent to the code VarE id ← [| foo |]
VarE id ← [| foo |]
. Note that this construct has a simple Name
type (not Q Exp
or Q Name
), so it can be used where it is not possible to use monads, for example: f ∷ Exp → Exp f (App (Var m) e) | m == 'map = …
[| … |]
[| … |]
. For example, it cannot be used inside these brackets (this is not possible: [| 'foo |]
), but it cannot be applied to it (this is also impossible: $( 'foo )
), because you need type Q …
to paste it Q …
More importantly, this form is defined statically, returning a fully qualified name, with unambiguous interpretation.[| P |]
[| P |]
means the data constructor P
, while [t| P |]
[t| P |]
means a type constructor. Therefore, for the "lightweight citation" requires the same way of separating these entities. For a type context, just two single quotes are used:'Foo
means “data constructor Foo
in the context of an expression”'foo
means “name foo
in the context of an expression”''Foo
means “constructor of type Foo
in the context of types”''foo
means “variable of type foo
in the context of types”Show
, which is disassembled at the end. report ∷ Bool → String → Q ()
report
function displays the message given in the second argument. If the first argument is True
, then the result is taken as an error, otherwise, the message is simply shown ( as warning ). In any case, calculations continue, if they need to be stopped, use monadic fail
. If there is no “closing” recover
, the compilation fails. recover ∷ Q a → Q a → Q a
recover ab
runs b
. If b
were calls to report True "…"
, then a is run. If b
completes without such errors, then its result is returned, and a
ignored. location ∷ Q Loc
Loc
structure) where the current gluing occurs - it may be convenient for error messages.-ddump-splices
, with which it shows the results of pasting all the top-level patterns during the loading of a module.Q
monad using the runQ
∷ Q a → IO a
function and output the result either as an abstract syntax (AST) or as the corresponding Haskell code: $ ghci –XTemplateHaskell … Prelude> :m + Language.Haskell.TH Prelude Language.Haskell.TH> runQ [| \x _ -> x |] >>= print LamE [VarP x_1,WildP] (VarE x_1) Prelude Language.Haskell.TH> runQ [| \x _ -> x |] >>= putStrLn . pprint \x_0 _ -> x_0
pprint
function prints Haskell code as it will be pasted into the program when compiled. For further examples, we write a simple pattern that generates a lambda expression, ignoring its arguments and returning this string: module Cnst where import Language.Haskell.TH cnst :: Int -> String -> Q Exp cnst ns = return (LamE (replicate n WildP) (LitE (StringL s)))
$ ghci -XTemplateHaskell Cnst.hs … *Cnst> runQ (cnst 2 "str") >>= print LamE [WildP,WildP] (LitE (StringL "str")) *Cnst> runQ (cnst 2 "str") >>= putStrLn . pprint \_ _ -> "str"
{-# LANGUAGE TemplateHaskell #-} module Main where import Language.Haskell.TH import Cnst -- cnst : cnst1 :: t -> [Char] cnst1 = $(cnst 1 "x") cnst2 :: t1 -> t2 -> [Char] cnst2 = $(cnst 2 "str") -- , 20 cnst20 = $(cnst 20 "foo") -- , runQ: main = do runQ(cnst 1 "x") >>= print runQ(cnst 2 "str") >>= print runQ(cnst 20 "foo") >>= print runQ(cnst 1 "x") >>= putStrLn.pprint runQ(cnst 2 "str") >>= putStrLn.pprint runQ(cnst 20 "foo") >>= putStrLn.pprint
showClause
function separately. {-# LANGUAGE TemplateHaskell #-} module Main where import Derive data T = A Int String | B Integer | C $(deriveShow ''T) main = print [A 1 "s", B 2, C] -- [A 1 "s",B 2,C]
{-# LANGUAGE TemplateHaskell #-} module Derive where import Language.Haskell.TH import Control.Monad data T1 = T1 -- , -- n genPE :: Int -> Q ([PatQ], [ExpQ]) genPE n = do ids <- replicateM n (newName "x") return (map varP ids, map varE ids) -- show : -- show (A x1 x2) = "A "++show x1++" "++show x2 showClause :: Con -> Q Clause showClause (NormalC name fields) = do -- , .. "A". nameBase let constructorName = nameBase name -- (pats,vars) <- genPE (length fields) -- (" "++show x1++...++"") [x1, ...] let f [] = [| constructorName |] f (v:vars) = [| " " ++ show $v ++ $(f vars) |] -- clause [conP name pats] -- (A x1 x2) (normalB (f vars)) [] -- "A"++" "++show x1++" "++show x2 -- , Show deriveShow :: Name -> Q [Dec] deriveShow t = do -- t TyConI (DataD _ _ _ constructors _) <- reify t -- show: -- show (A x1 x2) = "A "++show x1++" "++show x2 -- show (B x1) = "B "++show x1 -- show C = "C" showbody <- mapM showClause constructors -- -- (T1) (x = "text") showbody d <- [d| instance Show T1 where show x = "text" |] let [InstanceD [] (AppT showt (ConT _T1)) [FunD showf _text]] = d return [InstanceD [] (AppT showt (ConT t )) [FunD showf showbody]]
Source: https://habr.com/ru/post/133009/
All Articles