2011-10-26 44 views
7

我試圖讓下面的代碼工作:中調用Haskell的FFI功能PTRS由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; 

當我嘗試這樣做,但是,我得到一個錯誤信息:

error: too few arguments to function ‘sample_hs’

我猜測的語言之間的接口不工作怎麼樣我認爲會的。有沒有辦法做我想做的事情?

回答

12

有可能,FFI允許導出高階函數。一些修改你的Haskell是,雖然需要:通過明確FunPtr

{-# 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出口。爲了使其更清楚一點,我已經在這種情況下命名了高階型樣本。爲了能夠創建函數指針,您需要使用「包裝器」函數,因此需要額外的FFI聲明。

我還沒有測試過,但它應該可以正常工作,無論如何編譯。更多關於繁tr 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。

+0

我正在使用的函數簽名比這個例子複雜得多,後面是你的例子,它的工作完美,謝謝! –

4

雖然我找不到在FFI中指定它的子句,但我確信沒有函數會導出部分應用程序功能。對應

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

C定義

int sample_hs(int, int); 

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

此外,國外類型的語法不允許對出口的高階函數 - 這樣的函數指針永遠不會出現在C方的聲明。