为什么模板 Haskell 会添加意想不到的括号?
Why does Template Haskell add unexpected parens?
我有以下内容:
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) |]
我想$(zipN 2)
生成:
\f x y -> f <$> ZipList x <*> ZipList y
所以它的类型是 (a -> b -> c) -> [a] -> [b] -> [c]
。但是仔细查看 -ddump-splices
的输出并过滤掉噪音,我发现 $(zipN 2)
会生成:
\f x y -> f <$> ((ZipList x) <*> (ZipList y))
类型为 (a -> b) -> [a1 -> a] -> [a1] -> ZipList b
。同样,$(zipN 3)
生成:
\f x1 x2 x3 -> (f <$> ((ZipList x1) <*> ((ZipList x2) <*> (ZipList x3)))
所以看起来 $([|...|])
的每个实例都被替换为 (...)
而不是 ...
,这让我感到惊讶,因为文档似乎说成对的 $( )
和 [| |]
"cancelled out."
为什么模板 Haskell 会生成这个 AST,我该怎么做才能从中获取正确类型的函数?
<$>
和 <*>
都是左结合的。你把他们联系起来是对的。
您可以构建表达式,使运算符改为左关联。
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
我有以下内容:
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) |]
我想$(zipN 2)
生成:
\f x y -> f <$> ZipList x <*> ZipList y
所以它的类型是 (a -> b -> c) -> [a] -> [b] -> [c]
。但是仔细查看 -ddump-splices
的输出并过滤掉噪音,我发现 $(zipN 2)
会生成:
\f x y -> f <$> ((ZipList x) <*> (ZipList y))
类型为 (a -> b) -> [a1 -> a] -> [a1] -> ZipList b
。同样,$(zipN 3)
生成:
\f x1 x2 x3 -> (f <$> ((ZipList x1) <*> ((ZipList x2) <*> (ZipList x3)))
所以看起来 $([|...|])
的每个实例都被替换为 (...)
而不是 ...
,这让我感到惊讶,因为文档似乎说成对的 $( )
和 [| |]
"cancelled out."
为什么模板 Haskell 会生成这个 AST,我该怎么做才能从中获取正确类型的函数?
<$>
和 <*>
都是左结合的。你把他们联系起来是对的。
您可以构建表达式,使运算符改为左关联。
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