2011-06-03 13 views
11

Estoy comenzando Haskell y estaba buscando en algunas bibliotecas donde los tipos de datos se definen con "!". Ejemplo de la biblioteca ByteString:¿Cuál es el objetivo de la declaración de rigor?

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload 
        {-# UNPACK #-} !Int    -- offset 
        {-# UNPACK #-} !Int    -- length 

Ahora vi this question como una explicación de lo que esto significa y supongo que es bastante fácil de entender. Pero mi pregunta es ahora: ¿de qué sirve usar esto? Dado que la expresión se evaluará siempre que sea necesario, ¿por qué obligarías a la evaluación temprana?

En la segunda respuesta a esta pregunta C.V. Hansen dice: "[...] a veces la sobrecarga de la pereza puede ser demasiado o un desperdicio". ¿Se supone que eso significa que se usa para ahorrar memoria (guardar el valor es más barato que guardar la expresión)?

¡Una explicación y un ejemplo serían geniales!

Gracias!

[EDIT] Creo que debería haber elegido un ejemplo sin {- # UNPACK # -}. Así que déjame hacer uno yo mismo. ¿Esto alguna vez tendría sentido? Es sí, ¿por qué y en qué situación?

data MyType = Const1 !Int 
      | Const2 !Double 
      | Const3 !SomeOtherDataTypeMaybeMoreComplex 
+0

La pereza puede tener un montón de impacto en el código, la principal es que los programas de perezosos a menudo corren en el espacio lineal cuando los estrictos necesitan espacio constante. Pero en su ejemplo, la verdadera razón probablemente tiene que ver con que los datos en cuestión sean manipulados por funciones externas que no saben cómo forzar evaluaciones vagas. –

+0

No.El ForeignPtr se puede pasar a funciones externas, seguro, pero no a la estructura misma - incluso con anotaciones estrictas/desempaquetar no hay un ABI definido para las estructuras haskell nativas – bdonlan

Respuesta

13

El objetivo aquí no es tanto rigor como embalaje de estos elementos en la estructura de datos. Sin rigor, cualquiera de esos tres argumentos de constructor podría apuntar a una estructura de valor asignada en el montón o a un thunk de evaluación retardada asignada en el montón. Con rigor, solo podría apuntar a una estructura de valor asignada en el montón. Con rigurosidad y estructuras empaquetadas, es posible hacer esos valores en línea.

Como cada uno de estos tres valores es una entidad triple de tamaño y se accede estrictamente todos modos, forzando una estructura estricta y se envasa ahorra indirecciones puntero cuando se utiliza esta estructura.

En el caso más general, una anotación de rigurosidad puede ayudar a reducir las fugas de espacio. Consideremos un caso como este:

data Foo = Foo Int 

makeFoo :: ReallyBigDataStructure -> Foo 
makeFoo x = Foo (computeSomething x) 

Sin la anotación rigor, si llamas a makeFoo, se va a construir un puntero que Foo a un golpe seco que apunta a la ReallyBigDataStructure, manteniéndola en todo en la memoria hasta que algo obliga al procesador para evaluar . Si en lugar de tener

data Foo = Foo !Int 

Esto obliga a la evaluación computeSomething para proceder inmediatamente (así, tan pronto como algo fuerzas makeFoo sí mismo), lo que evita dejando una referencia a la ReallyBigDataStructure.

Tenga en cuenta que este es un caso de uso diferente que el código de cadena de bytes; el código bytestring fuerza sus parámetros con bastante frecuencia por lo que es poco probable que genere una fuga de espacio. Probablemente sea mejor interpretar el código bytestring como una optimización pura para evitar referencias al puntero.

+0

Tal vez debería haber elegido un ejemplo sin empaquetar/desempacar (no entiendo/no he mirado eso todavía). En cualquier caso, ¿qué quieres decir con entidad "tamaño de puntero"? Supongo que estoy un poco confundido acerca de los indicadores ya que, por lo que he entendido, Haskell realmente no tiene punteros. ¿Es esto algún tipo de cosa de menor nivel dependiente del compilador (que no es parte de haskell)? – o1iver

+0

Sí, esta es una optimización de bajo nivel de la representación de la memoria real de la estructura. – bdonlan

+0

OK, tiene sentido. Sin embargo, he editado mi respuesta y he agregado otro ejemplo (^^). ¿Es la misma respuesta válida en ese caso? – o1iver

Cuestiones relacionadas