views:

265

answers:

3

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.

+1  A: 

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 ()
Cetin Sert
A: 

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.

Norman Ramsey
+1  A: 

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.

Martijn