Haskell: ¿Cómo obtengo los valores de # constantes define-d?
Pregunta
En un programa Haskell, ¿cuál es la mejor manera de usar constantes definidas en los encabezados C?
Solución
Para esta tarea, hsc2hs es su amigo.
Para un ejemplo simple, obtengamos el valor de INT_MAX
de limits.h
.
$ cat >IntMax.hsc
module Main where
#include <limits.h>
c_INT_MAX = #const INT_MAX
main = print c_INT_MAX
Con hsc2hs, podemos #include
encabezados y usar los valores de las constantes con la directiva #const
.
En lugar de construir a mano, usa Cabal:
$ cat >intmax.cabal
Name: intmax
Version: 0.0
Cabal-Version: >=1.2
Build-Type: Simple
Executable intmax
Main-Is: IntMax.hs
Build-Depends: base
Observe que aunque el nombre del programa principal es IntMax.hsc
, la línea Main-Is
apunta a IntMax.hs
. Cuando Cabal busca IntMax.hs
pero encuentra IntMax.hsc
, lo alimenta automáticamente a través de hsc2hs como parte de la compilación.
$ cabal configure
Resolving dependencies...
Configuring intmax-0.0...
$ cabal build
Prerocessing executables for intmax-0.0...
Building intmax-0.0...
[1 of 1] Compiling Main ( dist\build\intmax\intmax-tmp\IntMax.hs, dist\build\intmax\intmax-tmp\Main.o )
Linking dist\build\intmax\intmax.exe ...
$ ./dist/build/intmax/intmax
2147483647
Tenga en cuenta que querrá dividir líneas con múltiples constantes. Digamos que está ensamblando un campo de bits para pasar a FormatMessage . Querrás escribirlo como
flags = #const FORMAT_MESSAGE_FROM_SYSTEM
.|.
#const FORMAT_MESSAGE_IGNORE_INSERTS
Ponerlos todos en una línea dará como resultado errores de sintaxis.
Otros consejos
GHC se está alejando de -fvia-c
y hacia -fasm
siempre que sea posible.
Un efecto secundario es que su programa puede compilarse sin usar ningún encabezado C, incluso en modo -fvia-c
, para garantizar que los resultados de la compilación sean funcionalmente idénticos a GHC en modo -fasm
.
Por lo tanto, es necesario utilizar hsc2hs
, c2hs
u otros preprocesadores que ejecuten antes GHC compila fuentes.
c2hs
admite de forma nativa las constantes enum
... ha pasado un tiempo, pero creo que algo así es correcto.
#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc
{#enum Foo#}
somethingBar = {#call pure something#} (cFromEnum Bar)
Las #define
'constantes son más complicadas. Siempre los he copiado en línea, o he usado C adicional para transformarlos en enumeraciones o variables constantes.