7

我一直在尝试按照此处找到的教程使用 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 文档,但对这类事情还不够精通,无法理解其中的大部分内容。

4

2 回答 2

6

该教程已过时。在 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除了模块之外,您还需要包ghcGHC.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 ()
于 2012-10-08T14:30:00.730 回答
2

这是动态加载的完整示例,也托管在此处

动态负载.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"
于 2014-02-22T17:02:47.123 回答