Dynamic Compilation in Haskell GHC API Error

拥有回忆 提交于 2019-12-04 05:05:10

The tutorial is out of date. In ghc-7.0.* and previous, the type of defaultErorHandler was

defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => DynFlags -> m a -> m a

and defaultDynFlags was just a value.

As of ghc-7.2.*, the type of defaultErrorHandler is

defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => LogAction -> m a -> m a

defaultDynFlags is a function

defaultDynFlags :: Settings -> DynFlags

and LogAction is a synonym

type LogAction = Severity -> SrcSpan -> PprStyle -> Message -> IO ()

In 7.6, it has changed again, we now have

defaultErrorHandler :: (ExceptionMonad m, MonadIO m) => FatalMessager -> FlushOut -> m a -> m a

with

type FatalMessager = String -> IO ()

and FlushOut being a newtype wrapper around IO ().

I'm not very familiar with the GHC Api (a too fast-moving target for me), so I'm not sure how the working code should look like, but for the 7.2 and 7.4 series, the first argument to defaultErrorHandler should probably be defaultLogAction.

Also the type of setContext has changed, I don't know if what I have does what you want, but it compiles (with 7.4.2; but you also need the ghc-paths package in addition to ghc for the GHC.Paths module) - I haven't tried to run it, though.

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 ()

Here is a complete example for dynamic loading, also hosted here:

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

And here is an example file to load:

DynTest.hs

module DynTest where


aString = "Hello"
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!