Para @KevinReid, he aquí un ejemplo de cómo hacerlo con c2hs.
Dada la enumeración key
en el archivo charm.h
(no tengo ni idea de lo que hay en la enumeración, por lo que acaba de llenar en unos pocos valores)
typedef enum
{
PLAIN_KEY = 0,
SPECIAL_KEY = 1,
NO_KEY = 2
}
key;
key get_key();
Puede utilizar el gancho de enumeración de c2hs así:
{#enum key as Key {underscoreToCase} deriving (Eq, Show)#}
Para enlazar a una función, puede usar call
o call
o fun
. call
es más simple, pero no hace ninguna clasificación. Aquí hay ejemplos de ambos. El get_key
envuelto en ffi devolverá un CInt, por lo que debe ordenarlo manualmente (si usa call
) o especificar el marcador de referencias (si usa fun
). c2hs no incluye señaleros de enumeración por lo que he escrito mi propio aquí:
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 generará la siguiente Haskell de esta (ligeramente limpiado):
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)
hsc2hs tiene una macro para esto, pero prefiero usar vainilla Haskell si es posible. – mcandre
No puede hacerlo en Haskell vainilla sin escribirlo todo de forma manual. Tanto hsc2hs como c2hs tienen enum hooks, y bindings-dsl usa macros de CPP. Estos generarán automáticamente el tipo de Haskell y la instancia de Enum para ti, pero no es Haskell vainilla. Por supuesto, podrías escribirlo, por ejemplo. c2hs, ejecute el preprocesador, luego envíe solo el archivo Haskell resultante, pero eso a menudo causará problemas con p. alineación y tamaños de ptr. –
La razón por la que necesita herramientas pesadas para hacer esto es que las constantes enum son una construcción en tiempo de compilación en C, no son símbolos exportados que pueden recuperarse mediante el enlace a la biblioteca, por lo que descubrir el valor de enums requiere analizar el texto fuente C. . –