2013-01-22 5 views
7

런타임에 TemplateHaskell 생성 코드를 생성하고 실행할 수 있습니까?런타임에 생성 된 TemplateHaskell 코드를 생성하고 실행할 수 있습니까?

나는, 실행시에, C를 사용하여 다음을 수행 할 수 있습니다

  • 함수의 소스 코드를 작성, GCC에
  • 콜 아웃이 .so를 (리눅스) (또는 사용 LLVM 등으로 컴파일 .),
  • .so를로드하고
  • 함수를 호출하십시오.

Template Haskell과 비슷한 점이 있습니까?

+0

템플릿 haskell 생성 된 코드는 런타임에 실행됩니다 : P – Satvik

+0

@Satvik - 분명히 생성 된 코드의 런타임에 있지만 생성기의 * 런타임에서 생성 된 코드를 실행하는 데 특별히 신경을 썼습니다. – fadedbee

답변

11

예, 가능합니다. GHC API는 Template Haskell을 컴파일합니다. 개념 증명은 https://github.com/JohnLato/meta-th에서 가능합니다. 매우 정교하지는 않지만 형식 안전성을 제공하는 하나의 일반 기술을 보여줍니다. 템플릿 하스켈 표현식은 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 소요되며, 먼저 일반 Exp를 만들 IO에서 실행됩니다. Exp은 런타임에 컴파일되고로드되는 소스 코드에 꽤 인쇄됩니다. 실제로, 나는보다 어려운 장애물 중 하나가 생성 된 TH 코드에서 올바른 수입을 지정하는 것을 발견했습니다.

+3

그건 약간 무서운 데요. –

4

GHC API을 사용하여 수행 할 수 있다고 생각되는 런타임시 코드를 만들고 실행하려면 이해하지만 무엇을 달성 할 수 있는지는 잘 모르겠습니다. 핫 코드 스와핑과 같은 것을 원하면 hotswap 패키지를 살펴보십시오.

+0

예, GHC API + Hotswap은 내가 원하는 것을 할 수 있습니다. – fadedbee