Haskell Language
Interface de fonction étrangère
Recherche…
Syntaxe
- import étranger ccall unsafe "foo" hFoo :: Int32 -> IO Int32 {- Importe une fonction nommée
foo
dans un fichier objet et définit le symbolehFoo
qui peut être appelé avec le code Haskell. -}
Remarques
Bien que cabal prenne en charge l'inclusion de bibliothèques C et C ++ dans un package Haskell, il existe quelques bogues. D'abord, si vous avez des données (plutôt qu'une fonction) définies dans bo
qui sont utilisées dans ao
, et répertoriez les C-sources: ac, bc
, alors cabal ne pourra pas trouver les données. Ceci est documenté dans # 12152 . Une solution de contournement lors de l'utilisation de cabal est de réorganiser la liste de C-sources
C-sources: bc, ac
pour qu'elle soit C-sources: bc, ac
. Cela peut ne pas fonctionner lorsque vous utilisez la pile, car la pile lie toujours les C-sources
ordre alphabétique, quel que soit l'ordre dans lequel vous les répertoriez.
Un autre problème est que vous devez entourer tout code C ++ dans les fichiers d'en-tête (.h) avec les gardes #ifdef __cplusplus
. C'est parce que GHC ne comprend pas le code C ++ dans les fichiers d'en-tête. Vous pouvez toujours écrire du code C ++ dans les fichiers d'en-tête, mais vous devez l'entourer de gardes.
ccall
fait référence à la convention d'appel ; actuellement ccall
et stdcall
(convention Pascal) sont supportés. Le mot clé unsafe
est facultatif; Cela réduit la surcharge pour les fonctions simples, mais peut provoquer des blocages si la fonction étrangère bloque indéfiniment ou si les autorisations d'exécution sont insuffisantes 1 .
Appeler C de Haskell
Pour des raisons de performances, ou en raison de l'existence de bibliothèques C matures, vous souhaiterez peut-être appeler du code C à partir d'un programme Haskell. Voici un exemple simple de la façon dont vous pouvez transmettre des données à une bibliothèque C et obtenir une réponse.
foo.c:
#include <inttypes.h>
int32_t foo(int32_t a) {
return a+1;
}
Foo.hs:
import Data.Int
main :: IO ()
main = print =<< hFoo 41
foreign import ccall unsafe "foo" hFoo :: Int32 -> IO Int32
Le mot-clé unsafe
génère un appel plus efficace que 'safe', mais requiert que le code C ne rappelle jamais le système Haskell. Puisque foo
est complètement en C et n'appellera jamais Haskell, nous pouvons utiliser unsafe
.
Nous devons également demander à cabal de compiler et de lier le code source C.
foo.cabal:
name: foo
version: 0.0.0.1
build-type: Simple
extra-source-files: *.c
cabal-version: >= 1.10
executable foo
default-language: Haskell2010
main-is: Foo.hs
C-sources: foo.c
build-depends: base
Ensuite, vous pouvez exécuter:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Passer Haskell fonctionne comme des rappels au code C.
Il est très courant que les fonctions C acceptent des pointeurs vers d'autres fonctions en tant qu'arguments. L'exemple le plus courant consiste à définir une action à exécuter lorsqu'un bouton est cliqué dans une bibliothèque de toolkit GUI. Il est possible de passer des fonctions Haskell en tant que rappels C.
Pour appeler cette fonction C:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
nous l'importons d'abord dans le code Haskell:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Maintenant, en regardant comment Object_Event_Cb
est défini dans l'en-tête C, définissez ce que Callback
est dans Haskell:
type Callback = Ptr () -> Ptr () -> IO ()
Enfin, créez une fonction spéciale qui FunPtr Callback
fonction Haskell de type Callback
dans un pointeur FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Maintenant, nous pouvons enregistrer le rappel avec le code C:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
Il est important de libérer FunPtr
alloué une fois que vous FunPtr
le rappel:
freeHaskellFunPtr cbPtr