Safe Haskell | Safe-Inferred |
---|---|
Language | Haskell2010 |
Refer to these examples.
Documentation
summon :: String -> Name -> Q Name Source #
Summons a Name
using template-haskell
's reify
function.
The first argument is a String
matching the Name
we want: either its
nameBase
, or qualified with its module. The second argument gives the
Name
to reify
.
If no match is found or there is some ambiguity, summon
will fail with
a list of Name
s found, along with the output of reify
for reference.
Suppose we are given a module M
that exports a function s
, but not
the type T
, the constrcutor C
, nor the field f
:
module M (s) where newtype T = C { f :: Int } s :: T -> T s = C . succ . f
In our own module we have no legitimate way of passing s
an argument of
type T
. We can get around this in a type-safe way with summon
:
{-# LANGUAGE TemplateHaskell #-} module Main where import Language.Haskell.TH.Syntax import Unsafe.TrueName import M type T = $(fmap ConT $ summon "T" 's) mkC :: Int -> T; unC :: T -> Int; f :: T -> Int mkC = $(fmap ConE $ summon "C" =<< summon "T" 's) unC $(fmap (`ConP` [VarP $ mkName "n"]) $ summon "C" =<< summon "T" 's) = n f = $(fmap VarE $ summon "f" =<< summon "T" 's) main :: IO () main = print (unC t, n) where t = s (mkC 42 :: T) n = f (s t)
Note that summon
cannot obtain the Name
for an unexported function,
since GHC does not currently return the RHS of function definitons.
The only workaround is to copypasta the definition. D:
truename :: QuasiQuoter Source #
A more convenient QuasiQuoter
interface to summon
.
The first space-delimited token gives the initial Name
passed to
summon
: it must be ‘quoted’ with a '
or ''
prefix to indicate
whether it should be interpreted in an expression or a type context,
as per the usual TH syntax.
Subsequent tokens correspond to the String
argument of summon
, and
are iterated over. Thus
[truename| ''A B C D |]
is roughly equivalent to:
summon "D" =<< summon "C" =<< summon "B" ''A
but with the resulting Name
wrapped up in ConE
, VarE
, ConP
, or
ConT
, depending on the context. (There is no quoteDec
.)
Variable bindings are given after a |
token in a Pat
context:
[truename| ''Chan Chan | chanR chanW |] <- newChan
These may be prefixed with !
or ~
to give the usual semantics.
A single ..
token invokes RecordWildCards
in Pat
contexts, and for
record construction in Exp
contexts.
Nested or more exotic patterns are not supported.
With this, the example from summon
may be more succinctly written:
{-# LANGUAGE QuasiQuotes #-} module Main where import Unsafe.TrueName import M type T = [truename| 's T |] mkC :: Int -> T; unC :: T -> Int; f :: T -> Int mkC = [truename| 's T C |] unC [truename| 's T C | n |] = n f = [truename| 's T f |] main :: IO () main = print (unC t, n) where t = s (mkC 42 :: T) n = f (s t)