HORIZON HASKELLDocslts/ghc-9.10.x248f8f02026-10-05Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · 248f8f0 · 2026-10-05

Modulehint-0.9.0.8Haskell2010

Language.Haskell.Interpreter

  • 14 types
  • 3 classes
  • 32 values
  • Packagehint-0.9.0.8
  • Exports49
  • LanguageHaskell2010
  • LicenceBSD-3-Clause
  • SourceInterpreterT.hs

The interpreter monad transformer

3 declarations
newtypenewtype InterpreterT (m :: Type -> Type) a
#
Instances9MonadTrans, Monad, Functor, Applicative, MonadIO, MonadCatch, …

Running the interpreter

Executes the interpreter. Returns Left InterpreterError in case of error.

NB. In hint-0.7.0 and earlier, the underlying ghc was accidentally overwriting certain signal handlers (SIGINT, SIGHUP, SIGTERM, SIGQUIT on Posix systems, Ctrl-C handler on Windows).

Interpreter options

valueset :: MonadInterpreter m => [OptionVal m] -> m ()
#

Use this function to set or modify the value of any option. It is invoked like this:

set [opt1 := val1, opt2 := val2,... optk := valk]
datadata Extension
#

This represents language extensions beyond Haskell 98 that are supported by GHC (it was taken from Cabal's Language.Haskell.Extension)

Constructors

Instances3Eq, Read, Show

When set to True, every module in every available package is implicitly imported qualified. This is very convenient for interactive evaluation, but can be a problem in sandboxed environments (e.g. System.Unsafe.unsafePerformIO is in scope).

Default value is True.

Observe that due to limitations in the GHC-API, when set to False, the private symbols in interpreted modules will not be in scope.

The search path for source files. Observe that every time it is set, it overrides the previous search path. The default is ["."].

Keep in mind that by a limitation in ghc, "." is always in scope.

Context handling

valueloadModules :: MonadInterpreter m => [String] -> m ()
#

Tries to load all the requested modules from their source file. Modules my be indicated by their ModuleName (e.g. "My.Module") or by the full path to its source file. Note that in order to use code from that module, you also need to call setImports (to use the exported types and definitions) or setTopLevelModules (to also use the private types and definitions).

The interpreter is reset both before loading the modules and in the event of an error.

IMPORTANT: Like in a ghci session, this will also load (and interpret) any dependency that is not available via an installed package. Make sure that you are not loading any module that is also being used to compile your application. In particular, you need to avoid modules that define types that will later occur in an expression that you will want to interpret.

The problem in doing this is that those types will have two incompatible representations at runtime: 1) the one in the compiled code and 2) the one in the interpreted code. When interpreting such an expression (bringing it to program-code) you will likely get a segmentation fault, since the latter representation will be used where the program assumes the former.

The rule of thumb is: never make the interpreter run on the directory with the source code of your program! If you want your interpreted code to use some type that is defined in your program, then put the defining module on a library and make your program depend on that package.

valuesetTopLevelModules :: MonadInterpreter m => [ModuleName] -> m ()
#

Sets the modules whose context is used during evaluation. All bindings of these modules are in scope, not only those exported.

Modules must be interpreted to use this function.

valuesetImports :: MonadInterpreter m => [ModuleName] -> m ()
#

Sets the modules whose exports must be in context. These can be modules previously loaded with loadModules, or modules from packages which hint is aware of. This includes package databases specified to unsafeRunInterpreterWithArgs by the -package-db=... parameter, and packages specified by a ghc environment file created by cabal build --write-ghc-environment-files=always.

Warning: setImports, setImportsQ, and setImportsF are mutually exclusive. If you have a list of modules to be used qualified and another list unqualified, then you need to do something like

 setImportsQ ((zip unqualified $ repeat Nothing) ++ qualifieds)
valuereset :: MonadInterpreter m => m ()
#

All imported modules are cleared from the context, and loaded modules are unloaded. It is similar to a :load in GHCi, but observe that not even the Prelude will be in context after a reset.

Module querying

typetype Id = String
#

An Id for a class, a type constructor, a data constructor, a binding, etc

Annotations

Type inference

valuetypeChecks :: MonadInterpreter m => String -> m Bool
#

Tests if the expression type checks.

NB. Be careful if unsafeSetGhcOption "-fdefer-type-errors" is used. Perhaps unsurprisingly, that can falsely make typeChecks and typeChecksWithDetails return True and Right _ respectively.

Evaluation

valueas :: Typeable a => a
#

Convenience functions to be used with interpret to provide witnesses. Example:

  • interpret "head [True,False]" (as :: Bool)
  • interpret "head $ map show [True,False]" infer >>= flip interpret (as :: Bool)
valueinfer :: Typeable a => a
#

Convenience functions to be used with interpret to provide witnesses. Example:

  • interpret "head [True,False]" (as :: Bool)
  • interpret "head $ map show [True,False]" infer >>= flip interpret (as :: Bool)
valuerunStmt :: MonadInterpreter m => String -> m ()
#

Evaluate a statement in the IO monad, possibly binding new names.

Example:

runStmt "x <- return 42"
runStmt "print x"

Error handling

3 declarations

Miscellaneous

4 declarations
valueghcVersion :: Int
#

Version of the underlying ghc api. Values are:

  • 804 for GHC 8.4.x

  • 806 for GHC 8.6.x

  • etc...

valueparens :: String -> String
#

Conceptually, parens s = "(" ++ s ++ ")", where s is any valid haskell expression. In practice, it is harder than this. Observe that if s ends with a trailing comment, then parens s would be a malformed expression. The straightforward solution for this is to put the closing parenthesis in a different line. However, now we are messing with the layout rules and we don't know where s is going to be used! Solution: parens s = "(let {foo =\n" ++ s ++ "\n ;} in foo)" where foo does not occur in s

classclass (forall (m :: Type -> Type). Monad m => Monad (t m)) => MonadTrans (t :: (Type -> Type) -> Type -> Type) where
#

The class of monad transformers. For any monad m, the result t m should also be a monad, and lift should be a monad transformation from m to t m, i.e. it should satisfy the following laws:

Since 0.6.0.0 and for GHC 8.6 and later, the requirement that t m be a Monad is enforced by the implication constraint forall m. Monad m => Monad (t m) enabled by the QuantifiedConstraints extension.

Ambiguity error with GHC 9.0 to 9.2.2

These versions of GHC have a bug (https://gitlab.haskell.org/ghc/ghc/-/issues/20582) which causes constraints like

(MonadTrans t, forall m. Monad m => Monad (t m)) => ...

to be reported as ambiguous. For transformers 0.6 and later, this can be fixed by removing the second constraint, which is implied by the first.

Methods

  • lift :: Monad m => m a -> t m a

    Lift a computation from the argument monad to the constructed monad.

Instances20MonadTrans, …
classclass Monad m => MonadIO (m :: Type -> Type) where
#

Monads in which IO computations may be embedded. Any monad built by applying a sequence of monad transformers to the IO monad will be an instance of this class.

Instances should satisfy the following laws, which state that liftIO is a transformer of monads:

Methods

  • liftIO :: IO a -> m a

    Lift a computation from the IO monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. IO is the base monad for the stack).

    Example
    import Control.Monad.Trans.State -- from the "transformers" library
    
    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

    Had we omitted liftIO, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

    The important part here is the mismatch between StateT s IO () and IO ().

    Luckily, we know of a function that takes an IO a and returns an (m a): liftIO, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"
    
    > evalStateT printState 3
    3
    
Instances37MonadIO, …