Estoy tratando de usar Data.Word pero ni siquiera entiendo su código fuente. Aquí hay algunas preguntas precisas que tengo, pero si tiene un mejor recurso para usar Word o bibliotecas similares, eso también podría ser útil.

Como referencia, veamos la implementación de Word8 (fuente)

data {-# CTYPE "HsWord8" #-} Word8 = W8# Word#
  1. ¿Cuáles son los # s? Por lo que puedo decir, no es parte del nombre o una función regular.
  2. ¿Cuál es la declaración antes de Word8 ({-# CTYPE "HsWord8" #-})? Los he visto como declaraciones de lenguaje al comienzo de los archivos, pero nunca en una definición.
  3. Por lo que puedo decir, W8 o W8# (ni siquiera sé cómo analizarlo) no está definido en ningún otro lugar del archivo o importado. ¿Se está definiendo implícitamente aquí o em me falta algo?
  4. De manera similar, Word# se usa en todas las definiciones de Word, pero no lo veo definido en ningún lado ... ¿de dónde viene y cómo puedo ver su definición?
2
Santiago Cuellar 29 abr. 2020 a las 22:52

2 respuestas

La mejor respuesta

¿Cuáles son las # s?

Son solo marginalmente más especiales que los W s, o s, r s, y d s, solo parte del nombre. El estándar Haskell no permite esto en un nombre, pero es solo una extensión sintáctica (llamada MagicHash): aquí no sucede nada profundo. Como convención, los componentes internos de GHC usan sufijos # en los tipos para indicar que no están en caja, y los sufijos # en los constructores para indicar que encajonan los tipos sin caja, pero estas son solo convenciones y el compilador no las aplica. o algo por el estilo.

¿Cuál es la declaración antes de Word8 ({-# CTYPE "HsWord8" #-})?

CTYPE declara que, cuando se usa la interfaz de funciones foráneas para ordenar este tipo a C, el tipo C apropiado para ordenarlo es HsWord8, un tipo definido en los encabezados C del tiempo de ejecución de GHC.

Por lo que puedo decir, W8 o W8# (ni siquiera sé cómo analizarlo) no está definido en ningún otro lugar del archivo o importado. ¿Se está definiendo implícitamente aquí?

Bueno, se está definiendo allí, pero no lo llamaría implícito; ¡Es bastante explícito! Considere esta típica declaración de datos de Haskell:

data Foo = Bar Field1 Field2

Define dos nuevos nombres: Foo, un nuevo tipo a nivel de tipo y Bar, una nueva función a nivel de cálculo que toma valores de tipo Field1 y Field2 y construye un valor de tipo Foo. Similar,

data Word8 = W8# Word#

Define un nuevo tipo Word8 y una nueva función constructora W8# :: Word# -> Word8.

De manera similar, Word# se usa en todas las definiciones de Word, pero no lo veo definido en ningún lado ... de dónde viene y cómo puedo ver su definición.

Word# puede importarse de GHC.Exts. Puede descubrirlo usted mismo a través de Hoogle. Es un compilador primitivo, por lo que, si bien es posible ver su fuente, lo que estaría viendo sería metacódigo, no código: no sería un código válido de Haskell que declarara el tipo con una declaración de datos estándar y una lista de constructores, sino más bien una combinación de código C y código Haskell que describe cómo colocar bits en la memoria, emitir instrucciones de ensamblaje para modificarlo e interactuar con el recolector de basura.

2
Daniel Wagner 29 abr. 2020 a las 21:27

Bueno, @DanielWagner cubrió la mayor parte de esto, pero estaba a punto de escribir esto, así que tal vez proporcione algunos detalles adicionales ... Originalmente estaba confundido sobre la naturaleza de las "definiciones" en GHC.Prim, Así que actualicé mi respuesta con una corrección.

Debería poder utilizar de manera efectiva los tipos Data.Word sin comprender el código fuente en GHC.Word.

Data.Word solo proporciona una familia de tipos integrales sin signo de tamaño de bits fijo (Word8, Word16, Word32 y Word64) más un tipo Word de "tamaño predeterminado" (el mismo tamaño que Int, por lo que 64 bits en arquitecturas de 64 bits). Debido a que todos estos tipos tienen instancias Num y Integral, las operaciones habituales en los enteros están disponibles y el desbordamiento se maneja de la manera habitual. Si desea utilizarlos como campos de bits, las instalaciones en Data.Bits serán útiles.

En particular, no veo nada en la fuente GHC.Word que pueda ayudarte a escribir código "normal" usando estos tipos.

Dicho esto, el carácter # normalmente no está permitido en los identificadores, pero puede permitirse (solo como un carácter final, por lo que W# está bien pero no bad#Identifier) al habilitar el < a href = "https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extension-MagicHash" rel = "nofollow noreferrer"> MagicHash extensión . No hay nada especial acerca de tales identificadores EXCEPTO que los identificadores específicos son tratados "mágicamente" por el compilador de GHC, y por convención estos identificadores mágicos, más algunos otros identificadores que en realidad no son "mágicos" pero están destinados solo para uso interno, use un carácter final # para marcarlos como especiales para que no los use accidentalmente alguien que intente escribir el código Haskell "normal".

Para ilustrar, en la definición:

data {-# CTYPE "HsWord8" #-} Word8 = W8# Word#

El identificador W8# es no mágico. Es solo un constructor regular que está destinado solo para uso interno, o al menos avanzado. Por otro lado, Word# es magia. GHC lo define internamente como un entero sin signo "sin caja" (64 bits en arquitecturas de 64 bits) donde "sin caja" aquí significa que se almacena directamente en la memoria en un campo de 8 bytes sin un campo adicional para su constructor.

Puede encontrar una "definición" sin sentido, en el código fuente de GHC.Prim:

data Word#

En el código normal de Haskell, esto definiría un tipo de datos Word# sin constructor. Tal tipo de datos estaría "deshabitado", lo que significa que no tiene valores posibles. Sin embargo, esta definición no se usa realmente. Este código fuente GHC.Prim se genera automáticamente para beneficio de la utilidad de documentación Haddock. En cambio, GHC.Prim es una especie de módulo virtual, y su implementación "real" está integrada en el compilador de GHC.

¿Cómo sabes qué identificadores que terminan en # son mágicos y cuáles no? Bueno, no lo sabes simplemente mirando los nombres. Creo que puede saber de manera confiable al registrar GHCi si están definidos en el módulo virtual GHC.Prim:

> :set -XMagicHash
> import GHC.Prim
> :i Word#
data Word# :: TYPE 'GHC.Types.WordRep   -- Defined in ‘GHC.Prim’

Cualquier cosa definida en GHC.Prim es mágica, y cualquier otra cosa no lo es. En el GHC.Prim generado fuente, estos identificadores mágicos aparecerán con definiciones sin sentido como:

data Foo#

O:

bar# = bar#

Las construcciones de la forma {-# WHATEVER #-} son pragmas del compilador. Proporcionan instrucciones especiales al compilador que se relacionan con el archivo fuente en su conjunto o, por lo general, con el código Haskell "cercano". Algunos pragmas se colocan en la parte superior del archivo fuente para habilitar extensiones de idioma o establecer marcas de compilación:

{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS_GHC -Wall #-}

Otros se entrelazan con el código Haskell para influir en las optimizaciones del compilador:

double :: Int -> Int
{-# NOINLINE double #-}
double x = x + x

O para especificar un diseño de memoria especial o manejo de estructuras de datos:

data MyStructure = MyS {-# UNPACK #-} !Bool {-# UNPACK #-} !Int

Estos pragmas están documentados en el manual de GHC. El CTYPE pragma es un pragma bastante oscuro que se relaciona con la forma en que se interpretará el tipo Word cuando se use con la interfaz de función externa y la convención de llamada capi. Si no planea llamar a funciones C desde un programa Haskell utilizando la convención de llamada capi, puede ignorarla.

2
K. A. Buhr 29 abr. 2020 a las 22:13