2012-02-08 72 views
23

我有一個現有的Haskell函數,它使用GHC API從模塊動態加載編譯後的代碼。它基於來自博客帖子Dynamic Compilation and Loading of Modules in Haskell的代碼。GHC API - 如何使用GHC 7.2從編譯模塊動態加載Haskell代碼?

該代碼在GHC 7.0中正常工作,但必須稍作修改才能在GHC 7.2中編譯,因爲GHC API已更改。

代碼現在拋出GHC 7.2運行時錯誤:

mkTopLevEnv: not a home module (module name):(function name) 

的代碼是

evalfuncLoadFFI String moduleName, 
       String externalFuncName, 
       String internalFuncName = do 

    result <- liftIO $ defaultRunGhc $ do 
    dynflags <- GHC.getSessionDynFlags 
    _ <- GHC.setSessionDynFlags dynflags 
    m <- GHC.findModule (GHC.mkModuleName moduleName) Nothing 

--------------------------------------------------------  
-- The following code works fine in GHC 7.0.4: 
-- 
-- GHC.setContext [] [(m, Nothing)] 
-- 
-- This new code attempts to set context to the module, 
-- but throws an error in GHC 7.2: 
-- 
    (_,oi) <- GHC.getContext 
    GHC.setContext [m] oi 
-------------------------------------------------------- 

    fetched <- GHC.compileExpr (moduleName ++ "." ++ externalFuncName) 
    return (Unsafe.Coerce.unsafeCoerce fetched :: [LispVal] -> IOThrowsError LispVal) 
    defineVar env internalFuncName (IOFunc result) 

僅供參考,完整的代碼可以在網上FFI.hs (github.com)

有沒有人有任何想法如何解決或解決這個問題?

此外,這可能是由GHC 7.2中的新安全Haskell更改引起的,還是僅僅是由於修改了GHC API?

回答

14

當您指定在上下文模塊當前模塊的上下文保留目前正在編譯的模塊,也就是說,他們必須明確是外部。

相反,您應該在setContext的第二個參數中指定想要的模塊作爲導入。這是可以做到像這樣:

GHC.setContext [] 
    -- import qualified Module 
    [ (GHC.simpleImportDecl . GHC.mkModuleName $ moduleName) 
    { GHC.ideclQualified = True 
    } 
    -- -- import qualified Data.Dynamic 
    -- , (GHC.simpleImportDecl . GHC.mkModuleName $ "Data.Dynamic") 
    -- { GHC.ideclQualified = True 
    -- } 
    ] 
fetched <- GHC.compileExpr $ moduleName ++ "." ++ externalFuncName 
return . unsafeCoerce $ fetched 
-- or: 
-- fetched <- GHC.dynCompileExpr $ moduleName ++ "." ++ externalFuncName 
-- return . fromDynamic (error "Illegal type cast") $ fetched 

PS:它可能是使用GHC.dynCompileExpr不是一個好主意,這樣就可以避開unsafeCoerce。您必須在上下文中爲Data.Dynamic添加合格的導入才能正常工作,但Data.Dynamic.Dynamic的值通常更合適,因爲您可以更優雅地處理類型錯誤。我在上面的代碼中添加了代碼。


更新

這裏是GHC 7.4.1語法:

GHC.setContext 
    -- import qualified Module 
    [ GHC.IIDecl $ 
    (GHC.simpleImportDecl . GHC.mkModuleName $ moduleName) 
    {GHC.ideclQualified = True} 
    ] 
+0

完美運作。感謝您的正確語法和詳細的解釋!享受你的賞金:) – 2012-02-14 17:37:20

+2

我還添加了GHC 7.4.1的語法,以防其他人受益。 – 2012-02-14 17:39:32

0

嘗試

GHC.setContext [] [(m,Nothing)] 

(從another StackOverflow question

+1

見我最近的編輯;這是我用於GHC 7.0的代碼。但API在GHC 7.2和7.4中改變了...... – 2012-02-12 17:07:19