从C调用Haskell FFI函数Ptrs

时间:2011-10-26 21:53:29

标签: c haskell ffi

我正在尝试使用以下代码:

sample_hs :: CInt -> (CInt -> CInt)
sample_hs x = (x+)

foreign export ccall sample_hs :: CInt -> (CInt -> CInt)

我希望能够在c:

中做到这样的事情
pf = sample_hs(2);
result = pf(3); //Should be 5;

然而,当我尝试这样做时,我收到一条错误消息:

  

错误:函数'sample_hs'的参数太少

我猜这个语言之间的界面不起作用我怎么想。有办法做我想做的事吗?

2 个答案:

答案 0 :(得分: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 ()

使用显式 FunPtr 类型在Haskell中导出高阶函数。为了清楚起见,我在这种情况下命名了更高阶的 Sample 。为了能够创建函数指针,您需要使用“包装器”函数,因此需要额外的FFI声明。

我没有对此进行测试,但它应该可以正常工作,无论如何都要编译。有关FunPtr的更多信息here

- 编辑我测试了它,它运行正常。按预期返回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+) 

并简单调用Hs2lib

PS C:\Users\Phyx\Desktop> hs2lib .\Test.hs
Linking main.exe ...
Done.

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);
}

所以这是非常简单的即插即用。但同样,它现在只适用于Windows。

答案 1 :(得分:4)

虽然我找不到在FFI中指定它的子句,但我很确定没有使用部分应用程序功能导出函数。与

对应的C声明
foreign export ccall sample_hs :: CInt -> CInt -> CInt

int sample_hs(int, int);

type int (*function_pointer)(int); // or whatever the right syntax is
function_pointer sample_hs(int);

此外,外部类型的语法禁止导出高阶函数 - 因此函数指针永远不会出现在C端的声明中。