Динамическая компиляция в Haskell GHC API Ошибка
Я пытался заставить базовую динамическую компиляцию кода работать с использованием GHC API, следуя инструкции, найденной здесь.
Этот код:
import GHC
import GHC.Paths
import DynFlags
import Unsafe.Coerce
main :: IO ()
main =
defaultErrorHandler defaultDynFlags $ do
func <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
target <- guessTarget "Test.hs" Nothing
addTarget target
r <- load LoadAllTargets
case r of
Failed -> error "Compilation failed"
Succeeded -> do
m <- findModule (mkModuleName "Test") Nothing
setContext [] [m]
value <- compileExpr ("Test.print")
do let value' = (unsafeCoerce value) :: String -> IO ()
return value'
func "Hello"
return ()
Должен получить функцию печати из другого файла с именем Test.hs, загрузить его и запустить функцию печати.
Я компилирую код с помощью GHC версии 7.4.1 с помощью команды:
ghc -package ghc --make Api.hs
Но получите следующую ошибку:
Api.hs:8:25:
Couldn't match expected type `Severity' with actual type `Settings'
Expected type: LogAction
Actual type: Settings -> DynFlags
In the first argument of `defaultErrorHandler', namely
`defaultDynFlags'
In the expression: defaultErrorHandler defaultDynFlags
Что я делаю неправильно? Я проверил документы по GHC API, но недостаточно разбираюсь в подобных вещах, чтобы понять большинство из них.
2 ответа
Учебник устарел. В ghc-7.0.* И предыдущих версиях defaultErorHandler
было
defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => DynFlags -> m a -> m a
а также defaultDynFlags
была просто ценность.
По состоянию на ghc-7.2.*, Тип defaultErrorHandler
является
defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => LogAction -> m a -> m a
defaultDynFlags
это функция
defaultDynFlags :: Settings -> DynFlags
а также LogAction
это синоним
type LogAction = Severity -> SrcSpan -> PprStyle -> Message -> IO ()
В 7.6 он снова изменился, теперь у нас есть
defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => FatalMessager -> FlushOut -> m a -> m a
с
type FatalMessager = String -> IO ()
а также FlushOut
быть newtype
обертка вокруг IO ()
,
Я не очень хорошо знаком с GHC Api (слишком быстро меняющаяся цель для меня), поэтому я не уверен, как должен выглядеть рабочий код, но для серий 7.2 и 7.4 - первый аргумент defaultErrorHandler
должно быть defaultLogAction
,
Также тип setContext
изменился, я не знаю, если то, что у меня есть, делает то, что вы хотите, но он компилируется (с 7.4.2; но вам также нужно ghc-paths
пакет в дополнение к ghc
для GHC.Paths
модуль) - я не пытался запустить его, хотя.
import GHC
import GHC.Paths
import DynFlags
import Unsafe.Coerce
main :: IO ()
main =
defaultErrorHandler defaultLogAction $ do
func <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
target <- guessTarget "Test.hs" Nothing
addTarget target
r <- load LoadAllTargets
case r of
Failed -> error "Compilation failed"
Succeeded -> do
m <- findModule (mkModuleName "Test") Nothing
setContext [IIModule m]
value <- compileExpr ("Test.print")
do let value' = (unsafeCoerce value) :: String -> IO ()
return value'
func "Hello"
return ()
Вот полный пример динамической загрузки, также размещенный здесь:
DynLoad.hs
-----------------------------------------------------------------------------
-- | Example for loading Haskell source code dynamically using the GHC api
-- Useful links:
-- GHC api:
-- http://www.haskell.org/ghc/docs/latest/html/libraries/ghc/GHC.html
-- Wiki:
-- http://www.haskell.org/haskellwiki/GHC/As_a_library
-----------------------------------------------------------------------------
module DynLoad where
import GHC
import GhcMonad (liftIO)
import GHC.Paths (libdir)
import Name (getOccString)
import Data.Dynamic (fromDyn)
-- | List all exports of this module
-- and evaluate a symbol from a module DynTest
main =
runGhc (Just libdir) $ do
putString ":::Display exports of modules:::"
modSums <- initSession ["DynLoad","DynTest"]
let thisModSum = head modSums
exports <- listExports thisModSum
mapM_ putString exports
putString ":::Evaluate a name from module DynTest:::"
importDecl_RdrName <- parseImportDecl "import DynTest as D"
setContext [IIDecl importDecl_RdrName]
dynVal <- dynCompileExpr "D.aString"
liftIO $ print $ (fromDyn dynVal "nope-nothing")
-- | Init interactive session and load modules
initSession modStrNames = do
dflags <- getSessionDynFlags
setSessionDynFlags $ dflags {
hscTarget = HscInterpreted
, ghcLink = LinkInMemory
}
targets <- mapM
(\modStrName -> do
putString modStrName
target <- guessTarget ("*"++modStrName++".hs") Nothing
return target
) modStrNames
setTargets targets
load LoadAllTargets
modSums <- mapM
(\modStrName -> do
putString modStrName
modSum <- getModSummary $ mkModuleName modStrName
return $ ms_mod modSum
) modStrNames
return modSums
-- | List exported names of this or a sibling module
listExports mod = do
maybeModInfo <- getModuleInfo mod
case maybeModInfo of
(Just modInfo) -> do
let expNames = modInfoExports modInfo
expStrNames = map getOccString expNames
return expStrNames
_ -> return []
-- | Util for printing
putString = liftIO . putStrLn
И вот пример файла для загрузки:
DynTest.hs
module DynTest where
aString = "Hello"