2011-10-26 13 views
7

estoy tratando de conseguir el código siguiente para trabajar:Calling Haskell FFI Función PAD de C

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

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

me gustaría ser capaz de hacer algo como esto en c:

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

Cuando trato de hacer esto, sin embargo, me sale un mensaje de error:

error: too few arguments to function ‘sample_hs’

que supongo que la interfaz entre el lenguaje no está funcionando cómo Pensé que sería. ¿Hay alguna forma de hacer lo que estoy tratando de hacer?

Respuesta

12

Es posible, FFI permite la exportación de funciones de orden superior. Algunas modificaciones a su Haskell se requiere sin embargo:

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

funciones de orden superior se exportan en Haskell utilizando el tipo explícita FunPtr. Para aclarar un poco, he nombrado el tipo ordenado más alto Sample en este caso. Para poder crear un puntero de función, necesita usar una función de "envoltura", de ahí la declaración adicional de FFI.

No he probado esto, pero debería funcionar bien, compila de todos modos. Más sobre FunPtr here

- EDIT Lo he probado y funciona bien. devuelve 5 como se esperaba.

Si por casualidad lo haces en Windows, tengo un paquete en hackage Hs2Lib que exportaría las funciones de Haskell y las compilaría a un .DLL automáticamente. También le proporciona incluye para C/C++ y C#. Sin embargo, si estás en Linux, aún estoy trabajando en eso.

enchufe descarado: P

Usando Hs2Lib la única cosa que hay en su archivo es:

module Test where 

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

y una simple llamada a Hs2lib

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

La razón de la IO y el retorno explícito es que Int -> (Int -> Int) es solo Int -> Int -> Int, ya que los tipos son correctos asociativos. Pero Int -> IO (Int -> Int) indica que desea devolver una función.Está en IO porque crear un puntero de función es una operación de efecto secundario. Para completar el archivo de C utilizado es:

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

así que es bastante plug-n-play. Pero, de nuevo, solo funciona para Windows por ahora.

+0

La firma de funciones con la que estaba trabajando era mucho más compleja que el ejemplo, siguió su ejemplo y funcionó perfectamente, ¡gracias! –

4

Aunque no puedo encontrar una cláusula que lo especifique en el FFI, estoy bastante seguro de que no se exportan funciones con capacidades parciales de aplicación. La declaración C correspondiente a

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

es

int sample_hs(int, int); 

no

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

Por otra parte, la sintaxis para este tipo de extranjeros prohíbe exportando funciones de orden superior - por lo que los punteros de función nunca aparecen en el declaraciones en el lado C.

Cuestiones relacionadas