GHC API - Как динамически загружать код на Haskell из скомпилированного модуля с использованием GHC 7.2? - PullRequest
24 голосов
/ 08 февраля 2012

У меня есть функция Haskell, которая использует GHC API для динамической загрузки скомпилированного кода из модуля. Он основан на коде из блога Динамическая компиляция и загрузка модулей в 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?

Ответы [ 2 ]

14 голосов
/ 14 февраля 2012

Текущий контекст модуля зарезервирован для модулей, которые в данный момент компилируются, т.е. когда вы указываете модули в контексте, они должны явно не быть внешними.

Вместо этого вы должны указать требуемый модуль в качестве импорта во втором аргументе 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 голосов
/ 11 февраля 2012

Попробуйте

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

(из другой вопрос StackOverflow )

...