用C+编写Haskell解释器+;(使用ghc或hugs作为库) 我正在编写一个C++应用程序,需要解释和评估Haskell代码。此代码在编译时未知,但由用户提供。 有没有办法将haskell编译器/解释器(如GHCi或hugs)用作库 我发现了FFI,但这似乎只适用于编译时已知的haskell代码 我找到了GHCAPI和提示,但它们似乎只有在我想从haskell中解释haskell代码时才起作用

用C+编写Haskell解释器+;(使用ghc或hugs作为库) 我正在编写一个C++应用程序,需要解释和评估Haskell代码。此代码在编译时未知,但由用户提供。 有没有办法将haskell编译器/解释器(如GHCi或hugs)用作库 我发现了FFI,但这似乎只适用于编译时已知的haskell代码 我找到了GHCAPI和提示,但它们似乎只有在我想从haskell中解释haskell代码时才起作用,c++,haskell,ghc,ghci,hugs,C++,Haskell,Ghc,Ghci,Hugs,由于GHC是用Haskell编写的,其API只能从Haskell获得。正如Daniel Wagner所建议的,在Haskell中编写所需的接口并用FFI将其绑定到C将是最简单的方法。这可能比使用GHCAPI到C的直接绑定更容易;你可以使用Haskell的优势来构建你需要的接口,并且只在顶层C++与它们进行接口。 请注意,Haskell的外国金融机构将只出口到C;如果你想在它周围有一个C++-ish的包装器,你就必须把它写成另一个层 (顺便说一句,Hugs是古老而未维护的。)我建议不要使用GHC

由于GHC是用Haskell编写的,其API只能从Haskell获得。正如Daniel Wagner所建议的,在Haskell中编写所需的接口并用FFI将其绑定到C将是最简单的方法。这可能比使用GHCAPI到C的直接绑定更容易;你可以使用Haskell的优势来构建你需要的接口,并且只在顶层C++与它们进行接口。 请注意,Haskell的外国金融机构将只出口到C;如果你想在它周围有一个C++-ish的包装器,你就必须把它写成另一个层


(顺便说一句,Hugs是古老而未维护的。)

我建议不要使用GHC api,而是为这种特殊的方法绑定,它只是GHC api的简化包装。我之所以推荐这一点,是因为GHCAPI的学习曲线有点陡峭

但不管怎样,正如我在评论中所说的,这取决于你希望这一过程深入到什么程度,需要的外国金融机构电话数量惊人地少。下面我给出一个示例,说明如何从加载的文件运行表达式并返回结果(仅当存在show实例时)。这只是基础,将结果作为结构返回也是可能的

module FFIInterpreter where

import Language.Haskell.Interpreter

import Data.IORef
import Foreign.StablePtr

type Session = Interpreter ()
type Context = StablePtr (IORef Session)

-- @@ Export
-- | Create a new empty Context to be used when calling any functions inside
--   this class.
--   .
--   String: The path to the module to load or the module name
createContext :: ModuleName -> IO Context
createContext name 
  = do let session = newModule name 
       _ <- runInterpreter session
       liftIO $ newStablePtr =<< newIORef session

newModule :: ModuleName -> Session
newModule name = loadModules [name] >> setTopLevelModules [name]

-- @@ Export
-- | free a context up
freeContext :: Context -> IO ()
freeContext = freeStablePtr

-- @@ Export = evalExpression
runExpr :: Context -> String -> IO String
runExpr env input
  = do env_value <- deRefStablePtr env
       tcs_value <- readIORef env_value
       result    <- runInterpreter (tcs_value >> eval input) 
       return $ either show id result
我们可以用一个简单的测试来测试

*FFIInterpreter> session <- createContext "Test"
*FFIInterpreter> runExpr session "bar 5"
"25"

如果在64位体系结构上

只需调用
Hs2lib

PS Haskell\FFIInterpreter> hs2lib .\FFIInterpreter.hs -n "HsInterpreter"
Linking main.exe ...
Done.
最后,您将得到一个包含

#ifdef __cplusplus
extern "C" {
#endif
// Runtime control methods
// HsStart :: IO ()
extern CALLTYPE(void) HsStart ( void );

// HsEnd :: IO ()
extern CALLTYPE(void) HsEnd ( void );

// createContext :: ModuleName -> IO (StablePtr (IORef (Interpreter ())))
//
// Create a new empty Context to be used when calling any functionsinside this class.
// String: The path to the module to load or themodule name
//
extern CALLTYPE(void*) createContext (wchar_t* arg1);

// freeContext :: StablePtr (IORef (Interpreter ())) -> IO ()
//
// free a context up
//
extern CALLTYPE(void) freeContext (void* arg1);

// evalExpression :: StablePtr (IORef (Interpreter ())) -> String -> IO String
extern CALLTYPE(wchar_t*) evalExpression (void* arg1, wchar_t* arg2);

#ifdef __cplusplus
}
#endif
<>我还没有测试C++的一面,但是没有理由不工作。
这是一个非常简单的示例,如果您将其编译为动态库,您可能希望重定向stdout、stderr和stdin。

我认为您找到了这两个重要部分,但您需要将它们结合起来!编写一些编译时间Haskell,它设置并使用GHC API,并通过FFI调用C++中的代码。但我从来没有真正做到过,所以我没有信心让这成为一个实际的答案。我确实希望有一个更简单的解决方案…愚蠢的解决方案:你可以通过系统调用将GHC(I)作为本机代码,而不是将其用作库。只是出于好奇,你想在多大程度上做到这一点?基本的工作流程取决于您希望达到的高级程度,需要的外国金融机构电话少得惊人。如果您只想加载一个文件并使用该文件运行表达式,这很容易做到。我还想问一下,您打算在哪个平台上运行此功能?如果是Windows,你可以尝试我的库HS2LIB来进行FFI绑定。我也想从C++运行Haskell解释器。既然你在5年前问过这个问题,你能分享一些经验吗?你有一些例子项目吗?非常感谢你的例子。不幸的是,我在linux上需要这个。我能做些什么来运行您的示例呢?示例中的Haskell代码是独立于平台的,因此在linux上也同样适用。hs2lib生成的haskell代码在linux上应该可以正常工作。只是由于种种原因,我从未让ghc在linux上编译动态libs。看见它可以帮助您生成编组和FFI代码,只需将-T标志传递给它以保留临时文件,您就可以从那里获得它。从那里到编译它是静态的/共享的lib。或者,您可以使用某种形式的IPC,只需要一个Haskell“服务器”和一个通过套接字或管道进行通信的C++客户端。然后把信息序列化。这将是另一种方法。但同样,上面的Haskell代码是独立于平台的。当使用ghci运行时,Haskell解释器确实可以工作。所以我只需要一个方法,用C++调用它。我试图直接使用ghc,但出现了“未定义引用”错误。我为此贴了另一个问题:(也许你可以帮我)。这个问题解决了。谢谢。看来从hackage链接的hs2lib的手册和主页都死了。此外,我无法构建haskell src exts。hs2lib死了吗?有继任者吗?
{- @@ HS2C  ModuleName "wchar_t*@8"         @@ -}
PS Haskell\FFIInterpreter> hs2lib .\FFIInterpreter.hs -n "HsInterpreter"
Linking main.exe ...
Done.
#ifdef __cplusplus
extern "C" {
#endif
// Runtime control methods
// HsStart :: IO ()
extern CALLTYPE(void) HsStart ( void );

// HsEnd :: IO ()
extern CALLTYPE(void) HsEnd ( void );

// createContext :: ModuleName -> IO (StablePtr (IORef (Interpreter ())))
//
// Create a new empty Context to be used when calling any functionsinside this class.
// String: The path to the module to load or themodule name
//
extern CALLTYPE(void*) createContext (wchar_t* arg1);

// freeContext :: StablePtr (IORef (Interpreter ())) -> IO ()
//
// free a context up
//
extern CALLTYPE(void) freeContext (void* arg1);

// evalExpression :: StablePtr (IORef (Interpreter ())) -> String -> IO String
extern CALLTYPE(wchar_t*) evalExpression (void* arg1, wchar_t* arg2);

#ifdef __cplusplus
}
#endif