从C调用Haskell FFI函数Ptrs [英] Calling Haskell FFI Function Ptrs from C
问题描述
我正在尝试使以下代码起作用:
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"功能
我猜想该语言之间的接口无法按我认为的那样工作.有办法做我想做的事吗?
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的更多信息,请此处 >
-编辑,我已经对其进行了测试,并且效果很好.按预期返回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.
I am trying to get the following code to work:
sample_hs :: CInt -> (CInt -> CInt)
sample_hs x = (x+)
foreign export ccall sample_hs :: CInt -> (CInt -> CInt)
I would like to be able to do something like this in c:
pf = sample_hs(2);
result = pf(3); //Should be 5;
When I try to do this, however, I get an error message:
error: too few arguments to function ‘sample_hs’
I am guessing that the interface between the language isn't working how I thought it would. Is there a way to do what I'm trying to do?
It is possible, FFI Does allow Higher-Order functions to be exported. Some modifications to your Haskell is required though:
{-# 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 ()
Higher-Order functions are exported in Haskell by using the explicit FunPtr type. Just to make it a bit clear I've named the higher ordered type Sample in this case. In order to be able to create a function pointer you need to use a "wrapper" function, hence the extra FFI declaration.
I haven't tested this, But it should work fine, It compiles anyway. More on FunPtr here
-- EDIT I have tested It and it works fine. returns 5 as expected.
If you're by any chance doing this on windows, I have a package on hackage Hs2Lib that would export Haskell functions and compile them to a .DLL automatically for you. It also provides you includes for C/C++ and C#. If You're on Linux however, I'm still working on that.
shameless plug :P
Using Hs2Lib the only thing you need in your file is:
module Test where
-- @@ Export
sample_hs :: Int -> IO (Int -> Int)
sample_hs x = return (x+)
and a simple call to Hs2lib
PS C:\Users\Phyx\Desktop> hs2lib .\Test.hs
Linking main.exe ...
Done.
The reason for the IO and explicit return is that Int -> (Int -> Int) is just Int -> Int -> Int, since types are right associative. But Int -> IO (Int -> Int) indicates that you want to return a function. It's in IO because creating a function pointer is a side-effecting operation. For completeness the C file used is:
#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);
}
So It's pretty plug-n-play. But again, It only works for Windows for now.
这篇关于从C调用Haskell FFI函数Ptrs的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!