用 C++ 编写 Haskell 解释器(使用 ghc 或 Hugs 作为库)
我正在编写一个需要解释和评估 haskell 代码的 C++ 应用程序。该代码在编译时未知,但由用户给出。 有没有办法使用 haskell 编译器/解释器(如 GHCi 或 Hugs)作为库?
- 我找到了 FFI,但这似乎只适用于编译时已知的 haskell 代码。
- 我找到了 GHC API 和提示,但它们似乎只在我想从 haskell 之外解释 haskell 代码时才起作用。
I'm writing a C++ application that needs to interpret and evaluate haskell code. This code isn't known at compile time but given by the user.
Is there a way to use a haskell compiler/interpreter (like GHCi or hugs) as a library?
- I found FFI but this seems only to work for haskell code that is known at compile time.
- I found the GHC API and hint, but they seem only to work when I want to interpret haskell code from out of haskell.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我建议不要使用 GHC api,而是针对这种特定方法绑定到 Hint,这只是一个GHC api 的简化包装器。我推荐这个的原因是因为 GHC api 的学习曲线有点陡峭。
但无论如何,就像我在评论中所说的那样,根据您想要的深度,需要的 FFI 电话数量出人意料地少。下面我给出了一个示例,说明如何从加载的文件运行表达式并返回结果(仅当存在 show 实例时)。这只是基础知识,以结构形式返回结果应该也是可能的。
由于我们必须退出 Haskell Land,所以我们必须有某种方法来引用上下文,我们可以使用
StablePtr
来做到这一点,我只需将其包装在IORef
中即可如果你想在未来改变事情,它是可变的。请注意,GHC API 不支持对内存缓冲区进行类型检查,因此您必须在加载之前将要解释的代码保存到临时文件中。-- @@
注解是我的工具Hs2lib的,如果你不用它,请不要介意。我的测试文件是
,我们可以使用一个简单的测试来测试它
所以是的,它在 Haskell 中工作,现在让它在 Haskell 之外工作。
只需在文件顶部添加一些有关 Hs2lib 如何编组
ModuleName
的说明,因为该类型是在没有源代码的文件中定义的。或者
如果在 64 位架构上,
只需调用
Hs2lib
并且您最终会得到一个包含文件,其中
我还没有测试 C++ 端,但没有理由它不工作。
这是一个非常简单的示例,如果将其编译为动态库,您可能想要重定向 stdout、stderr 和 stdin。
Instead of using the GHC api I would suggest binding to Hint for this particular approach, which is just a simplified wrapper around the GHC api. The reason I would recommend this is because the GHC api has a bit of a steep learning curve.
But anyway, Like I said In my comment, depending on how deep you want this to go it would require surprisingly few FFI calls. Below I give an example on how to run expressions from a loaded file and return the results (only if there's a show instance). This is just the basics, returning the results as a structure should be possible too.
Since we have to exit haskell land we have to have some way to refer to the Context, We can do this with a
StablePtr
and I just wrap it in anIORef
to make it mutable in case you want to change things in the future. Note that the GHC API does not support type checking an in-memory buffer, so you have to save the code you want to interpret to a temporary file before loading it.The
-- @@
Annotations are for my tool Hs2lib, don't mind them if you don't use it.My test file is
and we can test this using a simple test
So yeah, it works in Haskell, now to make it work outside of haskell.
Just add to the top of the file a few instructions for Hs2lib on how to marshal
ModuleName
because that type is defined in a file which it doesn't have the source to.or
if on a 64bit architecture,
and Just invoke
Hs2lib
And you'll end up with among others, an Include file with
I haven't tested the C++ side, but there's no reason it shouldn't work.
This is a very barebones example, if you compile it to a dynamic lib you probably want to redirect stdout, stderr and stdin.
由于 GHC 是用 Haskell 编写的,因此它的 API 只能从 Haskell 获得。正如 Daniel Wagner 所建议的,在 Haskell 中编写所需的接口并使用 FFI 将它们绑定到 C 将是最简单的途径。这可能比使用 GHC API 直接绑定到 C 更容易;你可以利用 Haskell 的优势来构建你需要的接口,并且只在顶层用 C++ 与它们交互。
注意Haskell的FFI只会导出到C;如果您想要一个类似 C++ 的包装器,则必须将其编写为另一层。
(顺便说一句,拥抱是古老的并且没有维护。)
Since GHC is written in Haskell, its API is exclusively available from Haskell. Writing the interfaces you need in Haskell and binding them to C with the FFI, as Daniel Wagner suggested, is going to be the simplest route. This is probably easier than using a direct binding of the GHC API to C would be; you get to use Haskell's strengths to build the interfaces you need, and only interface with them in C++ at the top layer.
Note that Haskell's FFI will only export to C; if you want a C++-ish wrapper around it, you'll have to write it as another layer.
(BTW, Hugs is ancient and unmaintained.)