2011-10-26 29 views
7

Tôi cố gắng để lấy mã sau đây để làm việc:Calling Haskell FFI Chức năng PTRs từ C

sample_hs :: CInt -> (CInt -> CInt) 
sample_hs x = (x+) 

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

Tôi muốn để có thể làm điều gì đó như thế này trong c:

pf = sample_hs(2); 
result = pf(3); //Should be 5; 

Khi Tuy nhiên, tôi cố gắng thực hiện việc này, tôi nhận được thông báo lỗi:

error: too few arguments to function ‘sample_hs’

Tôi đoán rằng giao diện giữa ngôn ngữ không hoạt động như thế nào Tôi nghĩ nó sẽ như thế. Có cách nào để làm những gì tôi đang cố gắng làm không?

Trả lời

12

Có thể, FFI Cho phép chức năng đặt hàng cao hơn được xuất. Một số sửa đổi Haskell của bạn là cần thiết mặc dù:

{-# 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() 

-bậc cao chức năng được xuất khẩu trong Haskell bằng công rõ ràng FunPtr loại. Chỉ cần để làm cho nó một chút rõ ràng tôi đã đặt tên theo thứ tự cao hơn loại mẫu trong trường hợp này. Để có thể tạo một con trỏ hàm, bạn cần sử dụng hàm "wrapper", do đó khai báo FFI bổ sung.

Tôi chưa thử nghiệm điều này, Nhưng nó sẽ hoạt động tốt, Nó vẫn biên dịch. Thông tin thêm về FunPtr here

- EDIT Tôi đã thử nghiệm Nó và nó hoạt động tốt. trả về 5 như mong đợi.

Nếu bạn có cơ hội thực hiện điều này trên cửa sổ, tôi có gói hack trên Hs2Lib sẽ xuất các chức năng của Haskell và biên dịch chúng thành .DLL tự động cho bạn. Nó cũng cung cấp cho bạn bao gồm C/C++ và C#. Tuy nhiên, nếu bạn đang sử dụng Linux, tôi vẫn đang làm việc đó.

không biết xấu hổ cắm: P

Sử dụng Hs2Lib điều duy nhất bạn cần trong tập tin của bạn là:

module Test where 

-- @@ Export 
sample_hs :: Int -> IO (Int -> Int) 
sample_hs x = return (x+) 

và một cuộc gọi đơn giản để Hs2lib

PS C:\Users\Phyx\Desktop> hs2lib .\Test.hs 
Linking main.exe ... 
Done. 

Lý do cho sự IO và trả về rõ ràng là Int -> (Int -> Int) chỉ là Int -> Int -> Int, vì các kiểu là kết hợp đúng. Nhưng Int -> IO (Int -> Int) chỉ ra rằng bạn muốn trả về một hàm.Đó là trong IO bởi vì việc tạo ra một con trỏ hàm là một hoạt động tác dụng phụ. Để hoàn tất, tệp C được sử dụng là:

#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); 
} 

Vì vậy, nó khá plug-n-play. Nhưng một lần nữa, nó chỉ hoạt động cho Windows ngay bây giờ.

+0

Chữ ký chức năng tôi đang làm việc phức tạp hơn nhiều so với ví dụ, theo ví dụ của bạn và nó hoạt động hoàn hảo, cảm ơn! –

4

Mặc dù tôi không thể tìm thấy mệnh đề chỉ định nó trong FFI, tôi khá chắc chắn rằng không có chức năng nào được xuất với khả năng ứng dụng một phần. Việc kê khai C tương ứng với

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

int sample_hs(int, int); 

không

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

Hơn nữa, cú pháp với nhiều loại ngoại cấm xuất khẩu chức năng bậc cao - vì vậy con trỏ chức năng không bao giờ xuất hiện trong khai báo ở phía C.

Các vấn đề liên quan