Динамическая компиляция в 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"
Другие вопросы по тегам