Add default QuasiQuoter(s)
Motivation
Language.Haskell.TH.Quote
gives us
data QuasiQuoter = QuasiQuoter {
-- | Quasi-quoter for expressions, invoked by quotes like @lhs = $[q|...]@
quoteExp :: String -> Q Exp,
-- | Quasi-quoter for patterns, invoked by quotes like @f $[q|...] = rhs@
quotePat :: String -> Q Pat,
-- | Quasi-quoter for types, invoked by quotes like @f :: $[q|...]@
quoteType :: String -> Q Type,
-- | Quasi-quoter for declarations, invoked by top-level quotes
quoteDec :: String -> Q [Dec]
}
The documentation suggests that
if you are only interested in defining a quasiquoter to be used for expressions, you would define a 'QuasiQuoter' with only 'quoteExp', and leave the other fields stubbed out with errors.
This is not ideal. There are a few problems:
The easiest path, which some packages take, is to write something like
myqq = QuasiQuoter
{ quoteExp = ... }
The error message produced when myqq
is used in the wrong context will not explain the problem at all; it'll just point out that there was an exception in Template Haskell code. The second problem is that using error
, even more informatively, will produce an overly verbose, poorly formatted message because GHC assumes that it represents a bug in the quasiquoter. The correct thing is instead to use fail
as usual.
Proposal
I suggest offering one or perhaps a couple of suitable "default" QuasiQuoter
definitions. These could look like so:
defaultQuasiQuoter :: QuasiQuoter
defaultQuasiQuoter = QuasiQuoter
{ quoteExp = \_ -> fail "This quasiquoter is not for use in expressions"
, quoteType = \_ -> fail "This quasiquoter is not for use in types"
, quotePat = \_ -> fail "This quasiquoter is not for use in patterns"
, quoteDec = \_ -> fail "This quasiquoter is not for producing declarations"
}
namedDefaultQuasiQuoter :: String -> QuasiQuoter
namedDefaultQuasiQuoter n = QuasiQuoter
{ quoteExp = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in expressions"
, quoteType = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in types"
, quotePat = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for use in patterns"
, quoteDec = \_ -> fail $ "The " ++ n ++ " quasiquoter is not for producing declarations"
}
Now users can write things like
myqq = (namedDefaultQuasiQuoter "myqq")
{ quoteExp = ... }
The documentation should also indicate that the unused fields should fail
rather than error
.