File: README.md

package info (click to toggle)
haskell-hint 0.9.0.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 228 kB
  • sloc: haskell: 2,006; makefile: 3
file content (77 lines) | stat: -rwxr-xr-x 2,851 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# hint

[![Build Status](https://travis-ci.com/haskell-hint/hint.svg?branch=master)](https://travis-ci.com/haskell-hint/hint)
[![Hackage](https://img.shields.io/hackage/v/hint.svg)](https://hackage.haskell.org/package/hint)

This library defines an Interpreter monad within which you can interpret
strings like `"[1,2] ++ [3]"` into values like `[1,2,3]`. You can easily
exchange data between your compiled program and your interpreted program, as
long as the data has a `Typeable` instance.

You can choose which modules should be in scope while evaluating these
expressions, you can browse the contents of those modules, and you can ask for
the type of the identifiers you're browsing.

It is, essentially, a huge subset of the GHC API wrapped in a simpler API.

## Limitations

It is possible to run the interpreter inside a thread, but you can't run two
instances of the interpreter simlutaneously.

GHC must be installed on the system on which the compiled executable is running.

Compatibility is kept with the three last major GHC releases. For example, if
the current version is GHC 8.6, `hint` will work on 8.6, 8.4 and 8.2.

## Example

    {-# LANGUAGE LambdaCase, ScopedTypeVariables, TypeApplications #-}
    import Control.Exception (throwIO)
    import Control.Monad.Trans.Class (lift)
    import Control.Monad.Trans.Writer (execWriterT, tell)
    import Data.Foldable (for_)
    import Data.Typeable (Typeable)
    import qualified Language.Haskell.Interpreter as Hint

    -- |
    -- Interpret expressions into values:
    --
    -- >>> eval @[Int] "[1,2] ++ [3]"
    -- [1,2,3]
    -- 
    -- Send values from your compiled program to your interpreted program by
    -- interpreting a function:
    --
    -- >>> f <- eval @(Int -> [Int]) "\\x -> [1..x]"
    -- >>> f 5
    -- [1,2,3,4,5]
    eval :: forall t. Typeable t
         => String -> IO t
    eval s = runInterpreter $ do
      Hint.setImports ["Prelude"]
      Hint.interpret s (Hint.as :: t)

    -- |
    -- >>> :{
    -- do contents <- browse "Prelude"
    --    for_ contents $ \(identifier, tp) -> do
    --      when ("put" `isPrefixOf` identifier) $ do
    --        putStrLn $ identifier ++ " :: " ++ tp
    -- :}
    -- putChar :: Char -> IO ()
    -- putStr :: String -> IO ()
    -- putStrLn :: String -> IO ()
    browse :: Hint.ModuleName -> IO [(String, String)]
    browse moduleName = runInterpreter $ do
      Hint.setImports ["Prelude", "Data.Typeable", moduleName]
      exports <- Hint.getModuleExports moduleName
      execWriterT $ do
        for_ exports $ \case
          Hint.Fun identifier -> do
            tp <- lift $ Hint.typeOf identifier
            tell [(identifier, tp)]
          _ -> pure ()  -- skip datatypes and typeclasses

Check [example.hs](examples/example.hs) for a longer example (it must be run
from hint's base directory).