【问题标题】:Calling Haskell FFI Function Ptrs from C从 C 调用 Haskell FFI 函数 Ptrs
【发布时间】:2011-10-26 21:53:28
【问题描述】:

我正在尝试让以下代码工作:

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”的参数太少

我猜这两种语言之间的界面并没有像我想象的那样工作。有没有办法做我想做的事?

【问题讨论】:

    标签: c haskell ffi


    【解决方案1】:

    有可能,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 ()
    

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

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

    -- EDIT 我已经测试过了,它工作正常。按预期返回 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。

    【讨论】:

    • 我使用的函数签名比示例复杂得多,按照您的示例,它运行良好,谢谢!
    【解决方案2】:

    虽然我在 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 端的声明中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-10
      • 2017-01-23
      • 2019-09-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多