Ответ 1
Для @KevinReid здесь приведен пример того, как это сделать с помощью c2hs.
Учитывая перечисление key
в файле charm.h
(я понятия не имею, что в перечислении, поэтому я просто заполнил несколько значений)
typedef enum
{
PLAIN_KEY = 0,
SPECIAL_KEY = 1,
NO_KEY = 2
}
key;
key get_key();
Вы можете использовать c2hs enum hook следующим образом:
{#enum key as Key {underscoreToCase} deriving (Eq, Show)#}
Для привязки к функции вы можете использовать либо call
, либо fun
. call
проще, но не делает маршалинга. Вот примеры того и другого. Ffi-wrapped get_key
вернет CInt, поэтому вам нужно либо вручную его маршалировать (при использовании call
), либо указать маршаллер (при использовании fun
). c2hs не включает маршаллеров enum, поэтому я написал здесь свой собственный:
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 из этого (слегка очищенный):
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)