[Haskell-cafe] Template Haskell question

宮里洸司 viercc at gmail.com
Wed Apr 28 08:42:42 UTC 2021


I've been digging through GHC source code to understand the reasons
behind these behaviors.

1. There are use-cases of TemplateHaskell which do not want duplicate variables
in patterns to be error. See a note in source code:

https://gitlab.haskell.org/ghc/ghc/-/blob/d04a758296afdfd12300b0466967a42276a2c5a8/compiler/GHC/ThToHs.hs#L1981

Quoting the linked note,

> Consider this TH term construction:
>   do { x1 <- TH.newName "x"   -- newName :: String -> Q TH.Name
>      ; x2 <- TH.newName "x"   -- Builds a NameU
>      ; x3 <- TH.newName "x"
>
>      ; let x = mkName "x"     -- mkName :: String -> TH.Name
>                               -- Builds a NameS
>
>      ; return (LamE (..pattern [x1,x2]..) $
>                LamE (VarPat x3) $
>                ..tuple (x1,x2,x3,x)) }
>
> It represents the term   \[x1,x2]. \x3. (x1,x2,x3,x)
>
> a) We don't want to complain about "x" being bound twice in
>    the pattern [x1,x2]
> b) We don't want x3 to shadow the x1,x2
> c) We *do* want 'x' (dynamically bound with mkName) to bind
>    to the innermost binding of "x", namely x3.
> d) When pretty printing, we want to print a unique with x1,x2
>    etc, else they'll all print as "x" which isn't very helpful

To do this, a variable name has one of these two flavors:
"system" flavor for names generated by `newName`, and "normal" flavor for names
made by `mkName`. Duplicate variable name error is not checked for
"system" flavored
names.

Actually, using `mkName` works in an intended way (cause error)

ghci> (\x $(varP (mkName "x")) -> x) 1 2

<interactive>:10:3: error:
    • Conflicting definitions for ‘x’
      Bound at: <interactive>:10:3
                <interactive>:10:7-23
    • In a lambda abstraction

2. Quoting brackets ([| ... |], [p| ... |]) are translated to TemplateHaskell
code (in Q Monad) by desugarar. The desugarar
represents *every* bound variable name by names generated by
TH.newName. For example, the desugared code of [| \x y -> x y y |]
looks like below:

    do { x <- newName "x"; y <- newName "y";
        return $ (LamE [VarP x, VarP y] (...) ) }

And [p| x |] is translated in this manner too, causing the discussed behavior.

-- 
/* Koji Miyazato <viercc at gmail.com> */


More information about the Haskell-Cafe mailing list