API GHC - Как динамически загружать код Haskell из скомпилированного модуля с использованием GHC 7.2?
У меня есть существующая функция Haskell, которая использует API GHC для динамической загрузки скомпилированного кода из модуля. Он основан на коде из сообщения блога Динамическая компиляция и загрузка модулей в Haskell.
Код отлично работает в GHC 7.0, но должен был быть слегка изменен для компиляции в GHC 7.2, потому что API GHC изменился.
Теперь код выдает ошибку времени выполнения в 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).
Кто-нибудь знает, как исправить или обойти эту проблему?
Кроме того, может ли это быть вызвано новыми изменениями Safe Haskell в GHC 7.2 или просто из-за изменений в API GHC?
Ответы
Ответ 1
Текущий контекст модуля зарезервирован для модулей, которые в настоящее время компилируются, то есть когда вы указываете модули в контексте, они должны явно не быть внешними.
Вместо этого вы должны указать желаемый модуль в качестве импорта во втором аргументе 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}
]
Ответ 2
Try
GHC.setContext [] [(m,Nothing)]
(from fooobar.com/info/225312/...)