对于我正在编写的工具(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
!! UPDATE !!
我发布了一个快速回答,但它在执行目录中创建了一个目标文件,任何提示都可以避免这种情况并避免使用所有文件IO。我还希望看到一个在内存中执行所有操作的版本:例如,用户在GUI中提供函数定义,编译/评估不会创建任何目标文件。
答案 0 :(得分:6)
使用hint。它是GHC API的类似GHCi的包装器,并不是很难使用。
如果您想要一个使用它的示例,我used it in my Yogurt project。
答案 1 :(得分: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 ()
答案 2 :(得分:4)
获得API的好工作。我可以告诉你一些代码生成器的工作原理。
GHC使用系统汇编程序创建.o文件。如果没有可用的选项让GHC自行清理,那么您应该使用http://hackage.haskell.org/trac/ghc/newticket?type=feature+request上的错误跟踪器向API提交功能请求。要提交请求,您需要注册一个帐户。
使用标准代码生成器,您将无法完全避免文件I / O,因为GHC将创建可重定位目标代码的工作委托给汇编程序。有一个基于LLVM的实验后端,可能能够在内存中完成所有操作,但如果在6.13之前的任何内容中可用,我会感到惊讶。但是,在GHC开发人员名单上可能值得一提。