Haskell Language
Interfaccia di funzioni estranee
Ricerca…
Sintassi
- importazione straniera ccall non sicuro "foo" hFoo :: Int32 -> IO Int32 {- Importa una funzione denominata
foo
in un file oggetto e definisce il simbolohFoo
che può essere chiamato con il codice Haskell. -}
Osservazioni
Mentre la cabal ha il supporto per includere le librerie C e C ++ in un pacchetto Haskell, ci sono alcuni bug. Innanzitutto, se si dispone di dati (piuttosto che di una funzione) definiti in bo
che sono utilizzati in ao
, ed elenca i C-sources: ac, bc
, quindi cabal non sarà in grado di trovare i dati. Questo è documentato in # 12152 . Una soluzione utilizzando cricca è quello di riordinare le C-sources
elenco da C-sources: bc, ac
. Questo potrebbe non funzionare quando si usa lo stack, perché lo stack collega sempre le C-sources
ordine alfabetico, indipendentemente dall'ordine in cui vengono elencate.
Un altro problema è che è necessario circondare qualsiasi codice C ++ nei file di intestazione (.h) con le protezioni #ifdef __cplusplus
. Questo perché GHC non capisce il codice C ++ nei file di intestazione. Puoi ancora scrivere codice C ++ nei file di intestazione, ma devi circondarlo di guardie.
ccall
riferisce alla convenzione di chiamata ; attualmente sono supportati ccall
e stdcall
(convenzione Pascal). La parola chiave unsafe
è facoltativa; questo riduce il sovraccarico per le funzioni semplici ma può causare deadlock se i blocchi di funzioni estranei indefinitamente o non dispone dell'autorizzazione sufficiente per l'esecuzione 1 .
Chiamando C da Haskell
Per motivi di prestazioni, o per l'esistenza di librerie C mature, potresti voler chiamare il codice C da un programma Haskell. Ecco un semplice esempio di come è possibile passare i dati a una libreria C e ottenere una risposta indietro.
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
La parola chiave unsafe
genera una chiamata più efficiente di "sicuro", ma richiede che il codice C non effettui mai una chiamata al sistema Haskell. Dato che foo
è completamente in C e non chiamerà mai Haskell, possiamo usare unsafe
.
Abbiamo anche bisogno di istruire la cabala per compilare e collegare in C source.
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
Quindi puoi eseguire:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Passare Haskell funziona come richiamata al codice C.
È molto comune che le funzioni C accettino i puntatori ad altre funzioni come argomenti. L'esempio più popolare è l'impostazione di un'azione da eseguire quando si fa clic su un pulsante in una libreria di toolkit GUI. È possibile passare le funzioni Haskell come callback C.
Per chiamare questa funzione C:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
per prima cosa lo importiamo nel codice Haskell:
foreign import ccall "header.h event_callback_add"
callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
Ora, osservando come Object_Event_Cb
è definito nell'intestazione C, definisci quale Callback
trova in Haskell:
type Callback = Ptr () -> Ptr () -> IO ()
Infine, crea una funzione speciale che FunPtr Callback
funzione Haskell di tipo Callback
in un puntatore FunPtr Callback
:
foreign import ccall "wrapper"
mkCallback :: Callback -> IO (FunPtr Callback)
Ora possiamo registrare il callback con il codice C:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
-- callback code
return ()
callbackAdd cpPtr
È importante liberare FunPtr
assegnato dopo aver annullato la registrazione della richiamata:
freeHaskellFunPtr cbPtr