Haskell Language
Buitenlandse functie-interface
Zoeken…
Syntaxis
- buitenlandse import ccall onveilige "foo" hFoo :: Int32 -> IO Int32 {- Importeert een functie met de naam
foo
in een objectbestand en definieert het symboolhFoo
dat kan worden opgeroepen met Haskell-code. -}
Opmerkingen
Hoewel cabal ondersteuning biedt voor het opnemen van een C- en C ++ -bibliotheken in een Haskell-pakket, zijn er enkele bugs. Ten eerste, als u gegevens (in plaats van een functie) gedefinieerd in zijn bo
die wordt gebruikt in ao
, en de lijst van de C-sources: ac, bc
, dan kliek zal niet in staat om de gegevens te vinden zijn. Dit is gedocumenteerd in # 12152 . Een tijdelijke oplossing bij het gebruik van kliek is om het herschikken C-sources
lijst te zijn C-sources: bc, ac
. Dit werkt mogelijk niet bij het gebruik van stapel, omdat stapel de C-sources
alfabetisch koppelt, ongeacht de volgorde waarin u ze vermeldt.
Een ander probleem is dat u C ++ -code in header (.h) -bestanden moet omringen met #ifdef __cplusplus
bewakers. Dit komt omdat GHC de C ++ -code in header-bestanden niet begrijpt. U kunt nog steeds C ++ -code in header-bestanden schrijven, maar u moet deze omringen met bewakers.
ccall
betrekking op de calling convention; momenteel worden ccall
en stdcall
(Pascal-conventie) ondersteund. Het unsafe
trefwoord is optioneel; dit vermindert overhead voor eenvoudige functies, maar kan deadlocks veroorzaken als de buitenlandse functie voor onbepaalde tijd blokkeert of onvoldoende toestemming heeft om uit te voeren 1 .
C bellen vanuit Haskell
Om prestatieredenen, of vanwege het bestaan van volwassen C-bibliotheken, kunt u de C-code van een Haskell-programma gebruiken. Hier is een eenvoudig voorbeeld van hoe u gegevens kunt doorgeven aan een C-bibliotheek en een antwoord kunt krijgen.
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
Het unsafe
trefwoord genereert een efficiëntere aanroep dan 'veilig', maar vereist dat de C-code nooit terugbelt naar het Haskell-systeem. Omdat foo
volledig in C staat en nooit Haskell zal bellen, kunnen we unsafe
.
We moeten ook cabal instrueren om te compileren en te koppelen in C-bron.
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
Dan kun je rennen:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Het doorgeven van Haskell functioneert als callbacks naar C-code.
Het is heel gebruikelijk dat C-functies verwijzingen naar andere functies als argumenten accepteren. Het meest populaire voorbeeld is het instellen van een actie die moet worden uitgevoerd wanneer op een knop wordt geklikt in een GUI-toolkitbibliotheek. Het is mogelijk om Haskell-functies door te geven als C-callbacks.
Om deze C-functie te gebruiken:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
we importeren het eerst naar Haskell-code:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Kijk nu hoe Object_Event_Cb
is gedefinieerd in de C-header en definieer wat Callback
is in Haskell:
type Callback = Ptr () -> Ptr () -> IO ()
Maak ten slotte een speciale functie die de Haskell-functie van het type Callback
in een pointer zou veranderen FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Nu kunnen we callback met C-code registreren:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
Het is belangrijk om toegewezen FunPtr
gratis te FunPtr
zodra u de terugbelaanmelding FunPtr
:
freeHaskellFunPtr cbPtr