针对 @KevinReid,这里有一个使用 c2hs 的示例。
假设在文件 charm.h
中有枚举类型 key
(我不知道枚举中具体包含哪些值,所以只填写了一些值)。
typedef enum
{
PLAIN_KEY = 0,
SPECIAL_KEY = 1,
NO_KEY = 2
}
key;
key get_key();
您可以像这样使用c2hs的enum钩子:
{#enum key as Key {underscoreToCase} deriving (Eq, Show)#}
要绑定到函数,您可以使用
call
或
fun
。
call
更简单,但不执行任何编组操作。以下是两者的示例。 ffi-wrapped
get_key
将返回CInt,因此您需要手动编组它(如果使用
call
)或指定编组程序(如果使用
fun
)。 c2hs不包括枚举编组器,因此我在此处编写了自己的编组器:
module Interface where
{#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代码(略有清理):
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)