19

对于我正在编写的工具(http://hackage.haskell.org/package/explore),我需要一种在运行时读取 haskell 函数定义的方法,将它们应用于我的工具中的值并检索其应用程序的结果.

谁能给我一个使用 GHC(6.10.4 或 6.12.1)API 的非常基本的示例?

在运行时从文件中读取的示例函数定义:

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

预期的程序输出

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

!!更新!!
我发布了一个快速答案,但它在执行目录中创建了一个目标文件,任何避免这种情况和避免所有文件 IO 的提示都是最受欢迎的。我还希望看到一个可以在内存中完成所有操作的版本:例如,用户在 GUI 中提供函数定义,并且编译/评估不会创建任何目标文件。

4

3 回答 3

6

使用提示。它是一个围绕 GHC API 的类似 GHCi 的包装器,使用起来并不难。

如果您想要一个使用示例,我在我的 Yogurt 项目中使用了它

于 2010-03-16T21:03:42.977 回答
5

改编自: 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 ()
于 2010-03-16T00:52:43.913 回答
4

很好的工作让 API 运行起来。我可以告诉你一些关于代码生成器是如何工作的。

GHC 使用系统汇编程序来创建一个 .o 文件。如果没有可用的选项让 GHC 自行清理,那么您应该使用http://hackage.haskell.org/trac/ghc/newticket?type=上的错误跟踪器向 API 提交功能请求功能+请求。为了提交请求,您需要注册一个帐户。

使用标准代码生成器,您将无法完全避免文件 I/O,因为 GHC 将创建可重定位目标代码的工作委托给了汇编器。有一个基于 LLVM 的实验性后端可能能够在内存中执行所有操作,但如果它在 6.13 之前的版本中可用,我会感到惊讶。然而,在 GHC 开发人员列表中询问可能是值得的。

于 2010-03-16T01:12:46.040 回答