第8章他言語関数インタフェース(FFI)

目次

8.1. FFI追補に対するGHCの拡張
8.1.1. 非ボックス化型
8.1.2. IOモナドを包むnewtype
8.1.3. プリミティブのインポート
8.2. GHCでFFIを使う
8.2.1. GHCでforeign exportforeign import ccall "wrapper"を使う
8.2.1.1. 自分で用意したmain()を使う
8.2.1.2. 他言語のコードから呼べるようなHaskellライブラリを作る
8.2.2. ヘッダファイルを使う
8.2.3. メモリ確保
8.2.4. マルチスレッドとFFI
8.2.4.1. foreign importとマルチスレッド
8.2.4.2. HaskellスレッドとOSスレッドの関係
8.2.4.3. foreign exportとマルチスレッド
8.2.4.4. hs_exit()の使用について
8.2.5. 浮動小数点とFFI

GHCは、Haskell 98の追補である他言語関数インタフェース1.0に(大部分)準拠している。これの定義はhttp://www.haskell.org/から得られる。

GHCでFFI対応を有効にするには、-XForeignFunctionInterfaceフラグを与えれば良い。

GHCには、FFI追補に対する固有の拡張がいくつか実装されている。これらの拡張は8.1. FFI追補に対するGHCの拡張に記述されている。これらの拡張を使ったプログラムは可搬でないということにどうか気を付けてほしい。従って、これらの機能は可能な限り避けるべきである。

FFIライブラリの説明は一緒に配布されているライブラリ説明書にある。例えばForeignモジュールを見よ。

FFI追補に対するGHCの拡張

この節で説明するFFIの機能はGHC特有のものである。これらを使った場合、他のコンパイラに対する可搬性がなくなる。

非ボックス化型

基本他言語型(FFI追補の3.2節を見よ)として、以下の型を使える。Int#Word#Char#Float#Double#Addr#StablePtr# aMutableByteArray#ForeignObj#ByteArray#

IOモナドを包むnewtype

FFIの仕様は、種々の箇所にIOモナドが現れることを要求するが、次のようにIOモナドをnewtypeで包むのが便利なことがある

  newtype MyIO a = MIO (IO a)

(このようなことをする理由としては、例えば、プログラムのある場所において、任意のIO手続きを呼ばれることを防ぎたい、というのが考えられる)

Haskell FFIは既に、他言語にインポート・エクスポートされるものの引数や結果がnewtypeだった場合、それらは自動的に外される、としている(FFI追補の3.2節)。GHCはこれを拡張して、IOモナド自体を包むnewtypeも自動的に外す。より正確にいうと、FFIの仕様がIO型を要求しているところならどこでも、IO型をnewtypeで包んだ物も認める。例えば、以下の宣言は問題ない。

   foreign import foo :: Int -> MyIO Int
   foreign import "dynamic" baz :: (Int -> MyIO Int) -> CInt -> MyIO Int

プリミティブのインポート

GHCはFFIを拡張して、primという呼び出し規約を追加している。例をあげる。

   foreign import prim "foo" foo :: ByteArray# -> (# Int#, Int# #)

これは、GHCの内部的な呼び出し規約に従う、Cmmコードで書かれた関数群をインポートするのに使う。この機能は、専らGHC付属の中核ライブラリでのみ使うことを意図している。さらなる詳細はGHC開発者wikiを見よ。