是否可以在运行时生成并运行TemplateHaskell生成的代码?

是否可以在运行时生成并运行TemplateHaskell生成的代码?

在运行时使用C,我可以:

  • 创建函数的源代码,
  • 调用gcc将其编译为.so(linux)(或使用llvm等),
  • 加载.so和
  • 调用该函数。

与模板Haskell类似的事情是否可能?

是的,这是可能的。 GHC API将编译模板Haskell。 可以在https://github.com/JohnLato/meta-th上获得概念validation,虽然不是很复杂,但它提供了一种通用技术,甚至提供了一些类型安全性。 使用Meta类型构建模板Haskell表达式,然后可以将其编译并加载到可用函数中。

 {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -Wall #-} module Data.Meta.Meta ( -- * Meta type Meta (..) -- * Functions , metaCompile ) where import Language.Haskell.TH import Data.Typeable as Typ import Control.Exception (bracket) import System.Plugins -- from plugins import System.IO import System.Directory newtype Meta a = Meta { unMeta :: ExpQ } -- | Super-dodgy for the moment, the Meta type should register the -- imports it needs. metaCompile :: forall a. Typeable a => Meta a -> IO (Either String a) metaCompile (Meta expr) = do expr' <- runQ expr -- pretty-print the TH expression as source code to be compiled at -- run-time let interpStr = pprint expr' typeTypeRep = Typ.typeOf (undefined :: a) let opener = do (tfile, h) <- openTempFile "." "fooTmpFile.hs" hPutStr h (unlines [ "module TempMod where" , "import Prelude" , "import Language.Haskell.TH" , "import GHC.Num" , "import GHC.Base" , "" , "myFunc :: " ++ show typeTypeRep , "myFunc = " ++ interpStr] ) hFlush h hClose h return tfile bracket opener removeFile $ \tfile -> do res <- make tfile ["-O2", "-ddump-simpl"] let ofile = case res of MakeSuccess _ fp -> fp MakeFailure errs -> error $ show errs print $ "loading from: " ++ show ofile r2 <- load (ofile) [] [] "myFunc" print "loaded" case r2 of LoadFailure er -> return (Left (show er)) LoadSuccess _ (fn :: a) -> return $ Right fn 

此函数采用ExpQ ,并首先在IO中运行它以创建普通的Exp 。 然后将Exp打印成源代码,在运行时编译和加载。 在实践中,我发现更难的障碍之一是在生成的TH代码中指定正确的导入。

根据我的理解,您希望在运行时创建和运行代码,我认为您可以使用GHC API执行,但我不太确定您可以实现的范围。 如果你想要热门代码交换,你可以看一下hotswap包。