2012-02-08 15 views
23

Tengo una función Haskell existente que usa la API GHC para cargar dinámicamente el código compilado de un módulo. Se basa en el código de la entrada del blog Dynamic Compilation and Loading of Modules in Haskell.GHC API - ¿Cómo cargar dinámicamente el código Haskell desde un módulo compilado utilizando GHC 7.2?

El código funciona bien en GHC 7.0, pero tuvo que modificarse ligeramente para compilarse en GHC 7.2, porque la API de GHC cambió.

Ahora, el código genera un error en tiempo de ejecución en GHC 7.2:

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

El código es

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) 

Como referencia, el código completo está disponible en línea en FFI.hs (github.com).

¿Alguien tiene alguna idea de cómo solucionar este problema o solucionar este problema?

Además, ¿podría deberse a los nuevos cambios de Safe Haskell en GHC 7.2, o es solo debido a modificaciones en la API de GHC?

Respuesta

14

El contexto actual módulo está reservado para los módulos que se están elaborando actualmente, es decir, cuando se especifica módulos en el contexto, deben explícitamente no ser externo.

En su lugar, debe especificar el módulo deseado como una importación, en el segundo argumento de setContext. Esto se puede hacer de esta manera:

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: podría ser una buena idea utilizar GHC.dynCompileExpr lugar, por lo que se puede evitar la unsafeCoerce. Debe agregar una importación calificada para Data.Dynamic en el contexto para que funcione, pero un valor Data.Dynamic.Dynamic generalmente es mejor para trabajar, ya que puede manejar los errores de tipo de forma más elegante. He agregado el código para eso como comentarios en el código anterior.


actualización

Y aquí es la sintaxis para GHC 7.4.1:

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

Eso funcionó perfectamente. ¡Gracias por la sintaxis adecuada y la explicación detallada! Disfruta de tu generosidad :) –

+2

También agregué la sintaxis para GHC 7.4.1 en caso de que pueda beneficiar a alguien más. –

0

Trate

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

(desde another StackOverflow question)

+1

Ver mi reciente edición; este es el código que estoy usando para GHC 7.0. Pero la API cambió en GHC 7.2 y 7.4 ... –

Cuestiones relacionadas