Вызов Ptrs функции FFI Haskell из C - PullRequest
7 голосов
/ 27 октября 2011

Я пытаюсь заставить работать следующий код:

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'

Я предполагаю, что интерфейс между языком нет 'работает так, как я думал.Есть ли способ сделать то, что я пытаюсь сделать?

Ответы [ 2 ]

12 голосов
/ 27 октября 2011

Возможно, 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 здесь

- РЕДАКТИРОВАТЬ Я проверил его, и он отлично работает. возвращает 5, как и ожидалось.

Если вы случайно сделаете это для Windows, у меня есть пакет для взлома 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.

Причина ввода-вывода и явного возврата заключается в том, что 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.

4 голосов
/ 27 октября 2011

Хотя я не могу найти пункт, который определяет его в FFI, я почти уверен, что никакие функции не экспортируются с частичными возможностями приложения. Декларация C, соответствующая

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

есть

int sample_hs(int, int);

не

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

Более того, синтаксис для внешних типов запрещает экспорт функций высшего порядка, поэтому указатели на функции никогда не появляются в объявлениях на стороне C.

...