使用 GHC API 评估 Haskell 语句/表达式
Posted
技术标签:
【中文标题】使用 GHC API 评估 Haskell 语句/表达式【英文标题】:Evaluation of Haskell Statements/Expressions using GHC API 【发布时间】:2011-01-27 22:11:53 【问题描述】:对于我正在编写的工具 (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 中提供函数定义,并且编译/评估不会创建任何目标文件。
【问题讨论】:
GHC API 在我 2006 年第一次尝试时非常适合我。我真的很想看看你得到什么答案。 +1 @Norman Ramsey:我刚刚发布了一个改编自 2008 年博客文章的答案。很惊讶地看到它“正常工作”:) 我想到了两个问题:1) 运行解释的代码是否可以接受?在这种情况下,您需要一个 API 进入 ghc 的交互部分,而不是编译器。 2)你需要在受限环境中执行代码吗?具体来说,您是否需要限制对 unsafePerformIO 等内容的访问? @MtnViewMark: 1) 是的,可以接受 2) 不一定,在我的场景中,用户在自己的计算机上运行应用程序,所以控制他们如何搞砸不是我的问题 【参考方案1】:使用hint。它是一个类似于 GHCi 的 GHC API 包装器,使用起来并不难。
如果你想要它的使用示例,我used it in my Yogurt project。
【讨论】:
【参考方案2】:改编自: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 ()
【讨论】:
非常感谢! setContext 在最近的版本中发生了变化,你会想要setContext [IIModule m]
。【参考方案3】:
很好地让 API 运行起来。我可以告诉你代码生成器的工作原理。
GHC 使用系统汇编程序创建一个 .o 文件。如果没有可用的选项让 GHC 自行清理,那么您应该使用 http://hackage.haskell.org/trac/ghc/newticket?type=feature+request 的错误跟踪器向 API 提交功能请求。为了提交请求,您需要注册一个帐户。
使用标准代码生成器,您将无法完全避免文件 I/O,因为 GHC 将创建可重定位目标代码的工作委托给了汇编器。有一个基于 LLVM 的实验性后端可能能够在内存中完成所有操作,但如果它在 6.13 之前的版本中可用,我会感到惊讶。不过,在 GHC 开发人员列表中询问可能是值得的。
【讨论】:
以上是关于使用 GHC API 评估 Haskell 语句/表达式的主要内容,如果未能解决你的问题,请参考以下文章
确保两个 (G) ADT 在 (GHC) Haskell 中具有相同的底层表示
haskell 代码可以在 leksah 上编译,但不能在 ghc 上编译