Why does Template Haskell add unexpected parens?
I have the following:
import Control.Applicative
import Control.Monad
import Language.Haskell.TH
mkExp :: [Name] -> ExpQ
mkExp (name:[]) = [| ZipList $(varE name) |]
mkExp (name:names) = [| ZipList $(varE name) <*> $(mkExp names) |]
zipN :: Int -> ExpQ
zipN n = do
names <- mapM newName $ replicate n "x"
fn <- newName "f"
let vps = map varP (fn:names)
lamE vps $ [| $(varE fn) <$> $(mkExp names) |]
I'd like $(zipN 2)
to generate:
f x y -> f <$> ZipList x <*> ZipList y
so that it has the type (a -> b -> c) -> [a] -> [b] -> [c]
. But poking around the output from -ddump-splices
and filtering out the noise, I've found that $(zipN 2)
instead generates:
f x y -> f <$> ((ZipList x) <*> (ZipList y))
with the type (a -> b) -> [a1 -> a] -> [a1] -> ZipList b
. Similarly, $(zipN 3)
generates:
f x1 x2 x3 -> (f <$> ((ZipList x1) <*> ((ZipList x2) <*> (ZipList x3)))
so it looks like each instance of $([|...|])
is being replaced with (...)
rather than ...
, which is surprising to me, since the docs seemed to say that pairs of $( )
and [| |]
[| |]
"cancelled out."
Why does Template Haskell generate this AST, and what can I do to get a function from it with the correct type?
Both <$>
and <*>
are left associative. You are right associating them.
You can build the expression so that the operators are left-associated instead.
mkExp' :: ExpQ -> [Name] -> ExpQ
mkExp' acc [] = acc
mkExp' acc (name:names) = mkExp'' [| $(acc) <$> ZipList $(varE name) |] names
where
mkExp'' acc [] = acc
mkExp'' acc (name:names) = mkExp'' [| $(acc) <*> ZipList $(varE name) |] names
zipN :: Int -> ExpQ
zipN n = do
names <- mapM newName $ replicate n "x"
fn <- newName "f"
let vps = map varP (fn:names)
lamE vps $ mkExp' (varE fn) names
链接地址: http://www.djcxy.com/p/33184.html
上一篇: 模板Haskell显示实例不工作