9

実行時に TemplateHaskell で生成されたコードを生成して実行することは可能ですか?

C を使用すると、実行時に次のことができます。

  • 関数のソースコードを作成し、
  • gcc を呼び出して .so (Linux) にコンパイルします (または llvm などを使用します)。
  • .so をロードし、
  • 関数を呼び出します。

Template Haskell でも同様のことが可能ですか?

4

2 に答える 2

13

はい、可能です。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 コードで正しいインポートを指定することであることがわかりました。

于 2013-01-22T13:49:47.867 に答える
5

私が理解していることから、 GHC APIを使用して実行できるコードを作成して実行したいと考えていますが、達成できる範囲についてはよくわかりません。ホット コード スワッピングのようなものが必要な場合は、パッケージhotswapを参照してください。

于 2013-01-22T13:26:47.380 に答える