2012-02-08 18 views
23

Ho una funzione Haskell esistente che utilizza l'API GHC per caricare dinamicamente il codice compilato da un modulo. Si basa sul codice dal post del blog Dynamic Compilation and Loading of Modules in Haskell.GHC API - Come caricare dinamicamente il codice Haskell da un modulo compilato usando GHC 7.2?

Il codice funziona correttamente in GHC 7.0, ma ha dovuto essere leggermente modificato per compilare in GHC 7.2, poiché l'API GHC è stata modificata.

Il codice ora genera un errore runtime in GHC 7.2:

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

Il codice è

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) 

Per riferimento, il codice completo è disponibile online in FFI.hs (github.com).

Qualcuno ha qualche idea su come risolvere o risolvere questo problema?

Inoltre, questo potrebbe essere causato dalle nuove modifiche di Safe Haskell in GHC 7.2, o è solo a causa di modifiche all'API GHC?

risposta

14

Il contesto modulo corrente è riservato per i moduli che sono attualmente in fase di compilazione, vale a dire quando si specifica moduli in contesto, devono esplicitamente non essere esterno.

Invece, è necessario specificare il modulo desiderato come importazione, nel secondo argomento di setContext. Questo può essere fatto in questo modo:

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: potrebbe essere una buona idea usare GHC.dynCompileExpr, invece, in modo che si può evitare il unsafeCoerce. È necessario aggiungere un'importazione qualificata per Data.Dynamic nel contesto in cui funziona, ma un valore Data.Dynamic.Dynamic è generalmente più piacevole con cui lavorare, dal momento che è possibile gestire gli errori di tipo in modo più agevole. Ho aggiunto il codice per questo come commenti nel codice sopra.


Aggiornamento

E qui è la sintassi per GHC 7.4.1:

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

Ciò ha funzionato perfettamente. Grazie per la corretta sintassi e spiegazione dettagliata! Goditi la tua generosità :) –

+2

Ho anche aggiunto la sintassi per GHC 7.4.1 nel caso in cui possa giovare a qualcun altro. –

0

Prova

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

(da another StackOverflow question)

+1

Vedere il mio recente modifica; questo è il codice che sto usando per GHC 7.0. Ma l'API è cambiata in GHC 7.2 e 7.4 ... –