scr*_*avy 6 haskell template-haskell implicit-parameters
有没有办法用隐式参数创建函数或使用模板haskell让绑定与隐式参数?
即使用模板haskell生成这样的签名是可能的:
doSomething :: (?context :: Context) => m a
Run Code Online (Sandbox Code Playgroud)
或者像这样的调用:
invoc = let ?context = newContext in doSomething
Run Code Online (Sandbox Code Playgroud)
我找不到合适的代数数据类型,也没有任何函数可以帮助我在模板haskell的API文档中讨论这个主题.我正在使用GHC 7.4.2.
如果模板haskell中没有对此扩展的本机支持,是否还有其他可能在编译期间注入代码(可能类似于模板haskell中的一般"代码注入函数"?).
编辑:我尝试了评论中的建议,这是发生的事情:
runQ [d| f :: (?c :: String) => Int ; f = 7 |]
<interactive>:10:17: parse error on input `c'
Run Code Online (Sandbox Code Playgroud)
这有效:
runQ [d| f :: Int ; f = 7|]
[SigD f_0 (ConT GHC.Types.Int),ValD (VarP f_0) (NormalB (LitE (IntegerL 7))) []]
Run Code Online (Sandbox Code Playgroud)
似乎没有得到支持.
这是一种非常脆弱但有效的方法。虽然您无法在模板 haskell 使用的 Exp 中引用 ?x ,但您可以引用另一个模块中的定义,例如:
reserved_prefix_x = ?x
Run Code Online (Sandbox Code Playgroud)
下面是一些代码,在一次 ghc 运行中生成如上所述的变量,在第二次 ghc 运行中,变量实际上引用隐式参数。
{-# LANGUAGE TemplateHaskell, NoMonomorphismRestriction #-}
module GenMod (h) where
import Data.Generics
import Data.IORef
import Data.List
import Language.Haskell.Meta.Parse as P
import Language.Haskell.TH
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax
import qualified Data.Set as S
import qualified Language.Haskell.Exts.QQ as Q
import System.IO.Unsafe
h = Q.hs { quoteExp = \s -> do
r <- either fail (upVars . return) (P.parseExp s)
writeMod'
return r
}
pfx = "q_"
{-# NOINLINE vars #-}
vars :: IORef (S.Set String)
vars = unsafePerformIO (newIORef S.empty)
writeMod' = runIO $ writeFile "GEN.hs" . ppMod =<< readIORef vars
writeMod = -- might be needed to avoid multiple calls to writeFile?
-- in this example this is called for every use of `h'
QuasiQuoter { quoteDec = \ _ -> do
writeMod'
[d| _ = () |] }
ppMod xs = "{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams #-}\n\
\module GEN where\n" ++
unlines (map (\x -> pfx ++ x ++ " = ?" ++ x) (S.toList xs))
upVars x = do
x' <- x
runIO $ modifyIORef vars (S.union (getMatchingVars x'))
runIO $ print =<< readIORef vars
return x'
getMatchingVars =
everything
S.union
(mkQ S.empty
(\ (OccName x) -> maybe S.empty S.singleton (stripPrefix pfx x)))
Run Code Online (Sandbox Code Playgroud)
使用准引号 GenMod.hs 的 Main.hs 文件:
{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams, QuasiQuotes, TemplateHaskell, CPP #-}
import GenMod
#ifndef stage1
import GEN
#endif
f_ = [h| q_hithere |]
Run Code Online (Sandbox Code Playgroud)
你必须调用 ghc 两次,例如:
ghci -Dstage1 Main.hs
GHCi, version 7.6.1: http://www.haskell.org/ghc/ :? for help
[1 of 2] Compiling GenMod ( GenMod.hs, interpreted )
[2 of 2] Compiling Main ( Ex.hs, interpreted )
fromList ["hithere"]
Ex.hs:8:6: Not in scope: `q_hithere'
Failed, modules loaded: GenMod.
Run Code Online (Sandbox Code Playgroud)
虽然 ghc 失败,但它仍然生成 GEN.hs,其中包含:
{-# LANGUAGE NoMonomorphismRestriction, ImplicitParams #-}
module GEN where
q_hithere = ?hithere
Run Code Online (Sandbox Code Playgroud)
当您加载 Main 时,它将在那里(省略 -D 标志)
*Main> :t f_
f_ :: (?hithere::t) => t
Run Code Online (Sandbox Code Playgroud)
这种麻烦或许不值得。也许从 TH 调用其他程序的其他情况更具激励性,例如对其他语言的内联调用http://hpaste.org/50837(gfortran 示例)
由于我使用了 haskell-src-meta 的默认解析器,因此准引用使用变量“reserved_prefix_x”而不是“?x”。应该可以毫无困难地接受“?x”。