Haskell Language                
            Интерфейс внешней функции
        
        
            
    Поиск…
Синтаксис
-  foreign import ccall unsafe «foo» hFoo :: Int32 -> IO Int32 {- импортирует функцию с именем fooв некоторый объектный файл и определяет символhFooкоторый можно вызвать с кодом Haskell. -}
замечания
 Хотя у cabal есть поддержка для включения библиотек C и C ++ в пакет Haskell, есть несколько ошибок. Во-первых, если у вас есть данные (а не функция), определенные в bo которые используются в ao , и перечислите C-sources: ac, bc , то cabal не сможет найти данные. Это подтверждено в # 12152 . Обходной путь при использовании cabal состоит в том, чтобы переупорядочить список C-sources как C-sources: bc, ac . Это может не работать при использовании стека, потому что стек всегда связывает C-sources алфавитном порядке, независимо от того, в каком порядке вы их перечисляете. 
 Еще одна проблема заключается в том, что вы должны окружать любой код C ++ в файлах заголовка (.h) с помощью #ifdef __cplusplus . Это связано с тем, что GHC не понимает код C ++ в файлах заголовков. Вы все еще можете писать код C ++ в заголовочных файлах, но вы должны окружить его защитой. 
 ccall относится к вызывающему соглашению ; в настоящее время ccall и stdcall (соглашение Pascal). unsafe ключевое слово необязательно; это уменьшает накладные расходы для простых функций, но может вызвать взаимоблокировки, если посторонняя функция блокирует бесконечно или имеет недостаточное разрешение для выполнения 1 . 
Вызов C из Haskell
По соображениям производительности или из-за наличия зрелых библиотек C вы можете вызвать код C из программы Haskell. Вот простой пример того, как вы можете передавать данные в библиотеку C и получать ответ.
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 ключевое слово генерирует более эффективный вызов, чем «безопасный», но требует, чтобы код C никогда не вызывал обратную связь с системой Haskell. Так как foo полностью в C и никогда не вызовет Haskell, мы можем использовать unsafe . 
Нам также необходимо дать инструкции cabal для компиляции и ссылки в источнике 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
Затем вы можете запустить:
> cabal configure
> cabal build foo
> ./dist/build/foo/foo
42
Передача Haskell выполняет функции обратного вызова кода C.
Для функций C очень часто принимают указатели на другие функции в качестве аргументов. Наиболее популярным примером является установка действия, которое будет выполняться при нажатии кнопки в некоторой библиотеке инструментов GUI. Функции Haskell можно передавать как C-обратные вызовы.
Чтобы вызвать эту функцию C:
void event_callback_add (Object *obj, Object_Event_Cb func, const void *data)
мы сначала импортируем его в код Haskell:
foreign import ccall "header.h event_callback_add"
    callbackAdd :: Ptr () -> FunPtr Callback -> Ptr () -> IO ()
 Теперь, посмотрев, как Object_Event_Cb определен в заголовке C, определите, что Callback находится в Haskell: 
type Callback = Ptr () -> Ptr () -> IO ()
 Наконец, создайте специальную функцию, которая будет обертывать функцию Haskell типа Callback в указатель FunPtr Callback : 
foreign import ccall "wrapper"
    mkCallback :: Callback -> IO (FunPtr Callback)
Теперь мы можем зарегистрировать обратный вызов с кодом C:
cbPtr <- mkCallback $ \objPtr dataPtr -> do
    -- callback code
    return ()
callbackAdd cpPtr
 Важно освободить выделенный FunPtr только вы FunPtr обратный вызов: 
freeHaskellFunPtr cbPtr