2012-02-15 23 views
8

Sé las diferencias entre data, newtype y type muy bien. Estoy escribiendo un pequeño script que construirá algún tipo de árbol de sintaxis. Casi todos los tipos tienen un constructor. Estoy evitando type para forzar la seguridad (múltiples tipos "diferentes" pueden terminar teniendo el mismo tipo en Haskell). No me importa la pereza/rigor en este caso, ni me importa el rendimiento (esta parte de ninguna manera es crítica para el rendimiento). Estoy centrado principalmente en el estilo. Tengo tres opciones:Otro nuevo tipo contra los datos (cuestión de estilo)

  1. Utilice solo data. Esto se siente bien, excepto que tengo muchos tipos con un solo constructor con un argumento. El código parece un tanto derrochador ... Aunque no me importa la ganancia de rendimiento, pero simplemente no me siento bien.
  2. Use solo newtype. Esto conduce a mucha fealdad con tuplas en el caso de múltiples parámetros.
  3. Mezcle data y newtype que de alguna manera se ven no uniformes y ligeramente molestos ... Prefiero tener todos los tipos declarados de una sola manera consistente.

estoy en un dilema de escoger entre 1 y 3.

Respuesta

11

En este caso, me gustaría utilizar data universalmente, por un par de razones. En primer lugar, para la coherencia con los casos de múltiples argumentos (que debe definitivamente ser data, no newtype).

En segundo lugar, y lo más importante, tiene newtypesemántica diferentes a data! El constructor de un newtype es estricto, a diferencia de los de data, que no son estrictos a menos que utilice explícitamente campos estrictos. Incluso si no le importa el rigor, o todos los campos de su data s son estrictos, todavía hay algunos subtle differences.

No creo que un solo constructor, un argumento data tipos son un desperdicio - sintácticamente, son tan ligeros como un newtype, y semánticamente, parece más importante para mí.

Usted ha dicho que no está preocupado por el rendimiento, pero si la sobrecarga de tiempo de ejecución de boxeo de un data era muy incómodo, entonces se podría mezclar ellos, siempre y cuando usted es consciente de las diferencias semánticas. Sin embargo, si usa -funbox-strict-fields, entonces GHC podría optimizar el único constructor, argumento único data s para usted, si ocurren como campos estrictos en otros tipos de datos.

Generalmente, debe usar newtype cuando está ajustando un tipo existente, para fines de seguridad/abstracción en tiempo de compilación, o para definir sus propias instancias, y use data siempre que el tipo simplemente esté compuesto por un campo único, en lugar de ser un contenedor.

6

Cuando estoy construyendo programas reales que no están haciendo las cosas sutiles con la pereza, casi siempre uso newtype para tipos de datos con un solo constructor y el argumento y data para todo lo demás:

data Foo = FooA | FooB Int 
data Bar = BarA Int Foo 
newtype Baz = Baz Bar 

En Por lo menos, si usted se encuentra escribiendo

newtype Foo = Foo (X,Y) 

la semántica son idénticos -

data Foo = Foo X Y 

por lo que también podría utilizar la versión data porque es más bonita. De hecho

data Foo = Foo Int 
newtype Bar = Bar Int 

difieren en la semántica, pero no de cualquier manera que termina siendo importante para los programas "reales", en la que no esperaba tener que saber la diferencia entre _|_ y Foo _|_ (ya que todos los valores son completamente definido de todos modos).

Hay otra cosa a tener en cuenta: uniformidad en las declaraciones es algo que debe ser cuidado de. Indica que hay un nivel de abstracción que no está codificando en su programa, que está dejando implícito. Vea si puede codificar ese nivel hasta que no quede estructura de declaración paralela para explotar. Esto no siempre es posible, pero trata de acercarte.

Cuestiones relacionadas