2012-02-08 20 views
23

Mam istniejącą funkcję Haskell, która używa GHC API do dynamicznego ładowania skompilowanego kodu z modułu. Jest oparty na kodzie z wpisu na blogu Dynamic Compilation and Loading of Modules in Haskell.GHC API - Jak dynamicznie ładować kod Haskella ze skompilowanego modułu za pomocą GHC 7.2?

Kod działa poprawnie w GHC 7.0, ale musiał zostać nieco zmodyfikowany, aby skompilować w GHC 7.2, ponieważ interfejs API GHC został zmieniony.

Kod teraz wyrzuca błąd wykonania w GHC 7.2:

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

Kod jest

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) 

Dla porównania, pełny kod jest dostępna online w FFI.hs (github.com).

Czy ktoś ma pomysł, jak rozwiązać ten problem lub rozwiązać ten problem?

Czy może to być spowodowane nowymi zmianami Safe Haskell w GHC 7.2, czy jest to spowodowane modyfikacjami GHC API?

Odpowiedz

14

Obecny kontekst moduł jest zarezerwowane dla modułów, które są aktualnie opracowywane, czyli gdy podasz moduły w kontekście, muszą wyraźnie nie być zewnętrzny.

Zamiast tego należy określić pożądany moduł jako import, w drugim argumencie setContext. Można to zrobić tak:

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: może to być dobry pomysł, aby użyć GHC.dynCompileExpr zamiast, tak aby można było uniknąć unsafeCoerce. Musisz dodać kwalifikowany import dla Data.Dynamic w kontekście, aby działał, ale wartość Data.Dynamic.Dynamic jest ogólnie przyjemniejsza do pracy, ponieważ możesz z większą łatwością obsługiwać błędy typu. Dodałem kod do tego jako komentarze w powyższym kodzie.


Aktualizacja

A oto składnia GHC 7.4.1:

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

To działało idealnie. Dziękuję za poprawną składnię i szczegółowe wyjaśnienie! Ciesz się swoją nagrodą :) –

+2

Dodałem także składnię GHC 7.4.1, która może przynieść korzyści każdemu. –

0

Spróbuj

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

(od another StackOverflow question)

+1

Zobacz mój ostatni zmienił; to jest kod, którego używam dla GHC 7.0. Ale interfejs API zmienił się w GHC 7.2 i 7.4 ... –