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