Evaluation of Haskell Statements/Expressions using GHC API
Asked Answered
W

3

19

For a tool I'm writing ( http://hackage.haskell.org/package/explore ) I need a way to read haskell function definitions at run-time, apply them to values from my tool and retrieve the results of their application.

Can anyone give me a very basic example using GHC (6.10.4 or 6.12.1) API?

example function definition to be read from a file at run-time:

f x = 10**(4/1102*x - 1)

expected program output

--mapM_ print $ map f [428, 410, 389]
3.577165388142748
3.077536885227335
2.5821307011665815

!!UPDATE!!
I posted a quick answer but it creates an object file in the directory of execution, any tips to avoid this and avoid all file IO is most welcome. I want to also see a version that does everything in memory: user provides the function definition in a GUI for example and the compilation / evaluation does not create any object files.

Walkon answered 16/3, 2010 at 0:12 Comment(4)
The GHC API gave me fits when I first tried it in 2006. I am really interested to see what answers you get. +1Bruise
@Norman Ramsey: I just posted an answer adapted from a blog post from 2008. Surprised to see it 'just work' :)Walkon
Two questions come to mind: 1) Would it be acceptable to run the code interpreted? In which case you want an API into the interactive parts of ghc, not the compiler. 2) Do you need to execute the code in a restricted environment? Specifically, do you need to limit access to things like unsafePerformIO?Jupiter
@MtnViewMark: 1) yes, it would be acceptable 2) not necessarily, in my scenario users run the app on their own computers so it is not my problem to control how they can mess stuff upWalkon
F
6

Use hint. It's a GHCi-like wrapper around the GHC API that is not very difficult to use.

If you want an example of its use, I used it in my Yogurt project.

Flathead answered 16/3, 2010 at 21:3 Comment(0)
W
5

adapted from: http://www.bluishcoder.co.nz/2008/11/dynamic-compilation-and-loading-of.html

f.hs:

module Func (Func.f) where

f :: Double -> Double
f x = 10**(4/1102*x - 1)

main.hs:

import GHC
import GHC.Paths
import DynFlags
import Unsafe.Coerce

import Control.Monad

main :: IO ()
main =
    defaultErrorHandler defaultDynFlags $ do
      func <- runGhc (Just libdir) $ do
        dflags <- getSessionDynFlags
        setSessionDynFlags dflags
        target <- guessTarget "f.hs" Nothing
        addTarget target
        r <- load LoadAllTargets
        case r of
          Failed -> error "Compilation failed"
          Succeeded -> do
            m <- findModule (mkModuleName "Func") Nothing
            setContext [] [m]
            value <- compileExpr ("Func.f")
            do let value' = (unsafeCoerce value) :: Double -> Double
               return value'
      let f = func
      mapM_ print $ map f [428, 410, 389]
      return ()
Walkon answered 16/3, 2010 at 0:52 Comment(1)
Thanks a ton! The setContext has changed in recent versions, you will instead want setContext [IIModule m].Chelsiechelsy
B
4

Nice work getting the API going. I can tell you a little bit about how the code generator works.

GHC uses the system assembler to create a .o file. If there is not an option available to get GHC to clean up after itself, then you should file a feature request against the API, using the bug tracker at http://hackage.haskell.org/trac/ghc/newticket?type=feature+request. In order to file the request, you will need to register an account.

Using the standard code generator, you will not be able to avoid file I/O entirely, just because GHC delegates the work of creating relocatable object code to the assembler. There is an experimental back end based on LLVM that might be able to do everything in memory, but I would be surprised if it is available in anything earlier than 6.13. However it could be worth asking on the GHC developers' list.

Bruise answered 16/3, 2010 at 1:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.