Szukaj…


Składnia

  • import zagraniczny ccall niebezpieczne „foo” hFoo :: Int32 -> IO Int32 {- Importuje funkcję o nazwie foo do jakiegoś pliku obiektowego i definiuje symbol hFoo który można wywołać za pomocą kodu Haskell. -}

Uwagi

Chociaż Cabal obsługuje obsługę bibliotek C i C ++ w pakiecie Haskell, istnieje kilka błędów. Po pierwsze, jeśli masz dane (a nie funkcję) zdefiniowane w bo które są używane w ao , i wymień C-sources: ac, bc , wtedy cabal nie będzie w stanie znaleźć danych. Jest to udokumentowane w # 12152 . Obejściem tego problemu jest zmiana kolejności listy C-sources C-sources: bc, ac . Może to nie działać podczas używania stosu, ponieważ stos zawsze łączy C-sources alfabetycznie, bez względu na kolejność ich wyświetlania.

Innym problemem jest to, że musisz otoczyć dowolny kod C ++ w plikach nagłówka (.h) za pomocą #ifdef __cplusplus . Wynika to z faktu, że GHC nie rozumie kodu C ++ w plikach nagłówkowych. Nadal możesz pisać kod C ++ w plikach nagłówków, ale musisz go otoczyć strażnikami.

ccall odnosi się do konwencji wywoływania ; obecnie ccallccall i stdcall (konwencja Pascala). unsafe słowo kluczowe jest opcjonalne; zmniejsza to narzut związany z prostymi funkcjami, ale może powodować zakleszczenia, jeśli obce bloki funkcyjne będą działać w nieskończoność lub nie będą miały wystarczających uprawnień do wykonania 1 .

Dzwonię do C z Haskell

Ze względu na wydajność lub z powodu istnienia dojrzałych bibliotek C możesz wywołać kod C z programu Haskell. Oto prosty przykład, w jaki sposób możesz przekazać dane do biblioteki C i uzyskać odpowiedź z powrotem.

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

unsafe słowo kluczowe generuje bardziej wydajne wywołanie niż „bezpieczne”, ale wymaga, aby kod C nigdy nie oddzwaniał do systemu Haskell. Ponieważ foo jest całkowicie w C i nigdy nie zadzwoni do Haskell, możemy użyć unsafe .

Musimy także poinstruować cabal, aby kompilował i łączył w źródle 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

Następnie możesz uruchomić:

> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42

Przekazywanie funkcji Haskell jako wywołań zwrotnych do kodu C.

Funkcje C bardzo często przyjmują wskaźniki jako argumenty dla innych funkcji. Najbardziej popularnym przykładem jest ustawienie akcji, która ma być wykonywana po kliknięciu przycisku w bibliotece narzędzi GUI. Możliwe jest przekazywanie funkcji Haskell jako wywołań zwrotnych C.

Aby wywołać tę funkcję C:

void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)

najpierw importujemy go do kodu Haskell:

foreign import ccall "header.h event_callback_add"
    callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()

Teraz patrząc na to, jak zdefiniowano Object_Event_Cb w nagłówku C, zdefiniuj, co jest Callback Object_Event_Cb w Haskell:

type Callback = Ptr () -> Ptr () -> IO ()

Na koniec utwórz specjalną funkcję, która FunPtr Callback funkcję Haskell typu Callback we wskaźnik FunPtr Callback :

foreign import ccall "wrapper"
    mkCallback :: Callback -> IO (FunPtr Callback)

Teraz możemy zarejestrować połączenie zwrotne za pomocą kodu C:

cbPtr <- mkCallback $ \objPtr dataPtr -> do
    -- callback code
    return ()
callbackAdd cpPtr

Ważne jest, aby zwolnić przydzielony FunPtr po wyrejestrowaniu oddzwaniania:

freeHaskellFunPtr cbPtr


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow