2013-01-22 16 views
7

Có thể tạo và chạy mã được tạo bởi TemplateHaskell khi chạy không?Có thể tạo và chạy mã được tạo bởi TemplateHaskell khi chạy không?

Sử dụng C, trong thời gian chạy, tôi có thể:

  • tạo mã nguồn của một hàm,
  • gọi ra gcc để biên dịch nó vào một .so (linux) (hoặc sử dụng llvm, vv .),
  • tải .so và
  • gọi hàm.

Điều tương tự cũng có thể xảy ra với Mẫu Haskell?

+0

Mã tạo mẫu được chạy lúc chạy: P – Satvik

+0

@Satvik - rõ ràng là thời gian chạy của mã được tạo, nhưng tôi đặc biệt xen kẽ trong việc chạy mã được tạo tại thời gian * của máy phát * – fadedbee

Trả lời

11

Có, có thể. API GHC sẽ biên dịch mẫu Haskell. Một chứng minh-khái niệm có sẵn tại https://github.com/JohnLato/meta-th, trong đó, mặc dù không phải là rất phức tạp, cho thấy một kỹ thuật chung mà thậm chí cung cấp một modicum của loại an toàn. Các biểu thức Haskell mẫu được xây dựng bằng cách sử dụng loại Meta, sau đó có thể được biên dịch và tải vào một hàm có thể sử dụng.

{-# 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 

chức năng này có một ExpQ, và lần đầu tiên chạy nó trong IO để tạo ra một đồng bằng Exp. Sau đó, Exp được in khá tốt vào mã nguồn, được biên dịch và tải vào thời gian chạy. Trong thực tế, tôi đã thấy rằng một trong những trở ngại khó khăn hơn là xác định chính xác nhập khẩu trong mã TH được tạo ra.

+3

Đó là một chút đáng sợ. –

4

Từ những gì tôi hiểu bạn muốn tạo và chạy mã khi chạy mà tôi nghĩ bạn có thể làm bằng cách sử dụng GHC API nhưng tôi không chắc chắn về phạm vi của những gì bạn có thể đạt được. Nếu bạn muốn một cái gì đó như trao đổi mã nóng, bạn có thể xem gói hotswap.

+0

Có, có vẻ như GHC API + Hotswap có thể làm những gì tôi đang tìm kiếm. – fadedbee