実行時に TemplateHaskell で生成されたコードを生成して実行することは可能ですか?
C を使用すると、実行時に次のことができます。
- 関数のソースコードを作成し、
- gcc を呼び出して .so (Linux) にコンパイルします (または llvm などを使用します)。
- .so をロードし、
- 関数を呼び出します。
Template Haskell でも同様のことが可能ですか?
実行時に TemplateHaskell で生成されたコードを生成して実行することは可能ですか?
C を使用すると、実行時に次のことができます。
Template Haskell でも同様のことが可能ですか?
はい、可能です。GHC API は Template Haskell をコンパイルします。概念実証は、https://github.com/JohnLato/meta-thで入手できます。これは、あまり洗練されていませんが、型の安全性を少しでも提供する 1 つの一般的な手法を示しています。テンプレート Haskell 式は型を使用して構築Meta
され、コンパイルして使用可能な関数にロードできます。
{-# 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
、実行時にコンパイルおよびロードされるソース コードにプリティ プリントされます。実際には、より困難な障害の 1 つは、生成された TH コードで正しいインポートを指定することであることがわかりました。
私が理解していることから、 GHC APIを使用して実行できるコードを作成して実行したいと考えていますが、達成できる範囲についてはよくわかりません。ホット コード スワッピングのようなものが必要な場合は、パッケージhotswapを参照してください。