2011-07-14 3 views
17

charm.cにenum keyがあり、key型の値を返す関数get_key()があるとします。HaskellとFFIを使用してC enumとどのようにインタフェースしますか?

対応するHaskell Keyレコードと関数getKey :: IO Keyを公開するにはどうすればよいですか?

そして、どのように単一の列挙値がどのようにHaskell値にマッピングされるかを手動で指定することなく、これを行うにはどうすればよいですか?

+0

hsc2hsを、このためのマクロを持っています可能であればバニラ・ハスケルを使っています。 – mcandre

+5

バニラ・ハスケルでは、すべて手作業で書くことはできません。 hsc2hsとc2hsは両方ともenumフックを持ち、bindings-dslはCPPマクロを使用します。これらはあなたのためにHaskell型とEnumインスタンスを自動生成しますが、バニラHaskellではありません。もちろん、あなたはそれを書き込むことができます。 c2hsを実行し、プリプロセッサを実行して、生成されたHaskellファイルを出力します。整列およびptrサイズ。 –

+9

これを行うためにヘビーなツールが必要な理由は、enum定数はCのコンパイル時の構造体であり、ライブラリにリンクして取り出すことができるエクスポートシンボルではないため、enumsの値を発見するにはCソーステキスト。 –

答えて

6

@KevinReidについては、c2hsでこれを行う方法の例です。

あなたはこのようc2hsの列挙型のフックを使用することができます(私は列挙型で何見当がつかないので、私はほんの数値で満たされた)ファイルcharm.h

typedef enum 
    { 
    PLAIN_KEY = 0, 
    SPECIAL_KEY = 1, 
    NO_KEY = 2 
    } 
key; 

key get_key(); 

を列挙keyを考える:

{#enum key as Key {underscoreToCase} deriving (Eq, Show)#} 

関数にバインドするには、callまたはfunのいずれかを使用できます。 callは簡単ですが、マーシャリングは行いません。両方の例があります。 ffi-wrapped get_keyはCIntを返しますので、手動でマーシャリング(callを使用する場合)またはマーシャラー(funを使用する場合)を指定する必要があります。

module Interface where -- file Interface.chs 

{#enum key as Key {underscoreToCase} deriving (Eq, Show)#} 

getKey = cIntToEnum `fmap` {#call get_key #} 

{#fun get_key as getKey2 { } -> `Key' cIntToEnum #} 

cIntToEnum :: Enum a => CInt -> a 
cIntToEnum = toEnum . cIntConv 

C2hsは(少しクリーンアップ)このことから、次のHaskellのが生成されます:私はここに私自身が書いたように、c2hsは、列挙型のマーシャラーが含まれていません

data Key = PlainKey 
     | SpecialKey 
     | NoKey 
     deriving (Eq,Show) 
instance Enum Key where 
    fromEnum PlainKey = 0 
    fromEnum SpecialKey = 1 
    fromEnum NoKey = 2 

    toEnum 0 = PlainKey 
    toEnum 1 = SpecialKey 
    toEnum 2 = NoKey 
    toEnum unmatched = error ("Key.toEnum: Cannot match " ++ show unmatched) 

getKey = cIntToEnum `fmap` get_key 

getKey2 :: IO (Key) 
getKey2 = 
    getKey2'_ >>= \res -> 
    let {res' = cIntToEnum res} in 
    return (res') 

cIntToEnum :: Enum a => CInt -> a 
cIntToEnum = toEnum . cIntConv 

foreign import ccall safe "foo.chs.h get_key" 
    get_key :: (IO CInt) 

foreign import ccall safe "foo.chs.h get_key" 
    getKey2'_ :: (IO CInt) 
+0

enumフックで定義されたenumのように、デフォルトのマーシャラが追加されました:https://github.com/haskell/c2hs/wiki/Implementation%20of%20Haskell%20Binding%20Modules。 – HaskellElephant

関連する問題