我试图让以下代码工作:
sample_hs :: CInt -> (CInt -> CInt)
sample_hs x = (x+)
foreign export ccall sample_hs :: CInt -> (CInt -> CInt)
Run Code Online (Sandbox Code Playgroud)
我希望能够在c中做这样的事情:
pf = sample_hs(2);
result = pf(3); //Should be 5;
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试这样做时,我收到一条错误消息:
错误:函数'sample_hs'的参数太少
我猜这个语言之间的接口不起作用我怎么想.有没有办法做我想做的事情?
Phy*_*hyx 12
有可能,FFI允许导出高阶函数.但是,您需要对Haskell进行一些修改:
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
import Foreign.C.Types
import Foreign
foreign export ccall sample_hs :: CInt -> IO (FunPtr Sample)
type Sample = CInt -> CInt
foreign import ccall "wrapper" mkSample :: Sample -> IO (FunPtr Sample)
sample_hs :: CInt -> IO (FunPtr Sample)
sample_hs x = mkSample (x+)
main = return ()
Run Code Online (Sandbox Code Playgroud)
通过使用显式FunPtr类型在Haskell中导出高阶函数.为了使它有点清楚我在这种情况下命名了更高阶的类型Sample.为了能够创建函数指针,您需要使用"包装器"函数,因此需要额外的FFI声明.
我没有测试过这个,但它应该工作正常,无论如何它都会编译.更多关于FunPtr的信息
- 编辑我测试了它,它工作正常.按预期返回5.
如果您有任何机会在Windows上执行此操作,我有一个关于hackage Hs2Lib的包,它将导出Haskell函数并自动将它们编译为.DLL.它还为您提供C/C++和C#.如果你在Linux上,我仍然在努力.
无耻插头:P
使用Hs2Lib,您在文件中唯一需要的是:
module Test where
-- @@ Export
sample_hs :: Int -> IO (Int -> Int)
sample_hs x = return (x+)
Run Code Online (Sandbox Code Playgroud)
并简单地调用Hs2lib
PS C:\Users\Phyx\Desktop> hs2lib .\Test.hs
Linking main.exe ...
Done.
Run Code Online (Sandbox Code Playgroud)
IO和显式返回的原因是Int - >(Int - > Int)只是Int - > Int - > Int,因为类型是右关联的.但Int - > IO(Int - > Int)表示您想要返回一个函数.它在IO中,因为创建一个函数指针是一个副作用操作.为了完整性,使用的C文件是:
#include <stdio.h>
#include <stdlib.h>
#include "Hs2lib_FFI.h"
/*
*
*/
int main(int argc, char** argv) {
HsStart();
CBF1_t pf = sample_hs(2);
int result = pf(3);
printf("%d\n", result);
HsEnd();
return (EXIT_SUCCESS);
}
Run Code Online (Sandbox Code Playgroud)
所以这是非常简单的即插即用.但同样,它现在只适用于Windows.