从C调用Haskell FFI函数Ptrs [英] Calling Haskell FFI Function Ptrs from C

查看:92
本文介绍了从C调用Haskell FFI函数Ptrs的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆