Diferencia entre `data` y` newtype` en Haskell

191

¿Cuál es la diferencia cuando escribo esto?

data Book = Book Int Int

versus

newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
ewggwegw
fuente
Deberías buscar un poco, esta pregunta ya ha sido respondida. stackoverflow.com/questions/2649305/…
tehman
Relacionado con stackoverflow.com/questions/2649305/…
Don Stewart
También relacionado: usos para newtype: stackoverflow.com/questions/991467/…
Don Stewart
25
Tenga en cuenta que newtype Book = Book Int Intno es válido. Sin embargo, puede tener newtype Book = Book (Int, Int)lo señalado por dons a continuación.
Edward KMETT

Respuestas:

241

Gran pregunta!

Hay varias diferencias clave.

Representación

  • A newtypegarantiza que sus datos tendrán exactamente la misma representación en tiempo de ejecución, que el tipo que ajusta.
  • Mientras datadeclara una nueva estructura de datos en tiempo de ejecución.

Entonces, el punto clave aquí es que newtypese garantiza que la construcción para el se borrará en el momento de la compilación.

Ejemplos:

  • data Book = Book Int Int

datos

  • newtype Book = Book (Int, Int)

nuevo tipo

Observe cómo tiene exactamente la misma representación que a (Int,Int), ya que el Bookconstructor se borra.

  • data Book = Book (Int, Int)

tupla de datos

Tiene un Bookconstructor adicional no presente en el newtype.

  • data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int

ingrese la descripción de la imagen aquí

No hay punteros! Los dos Intcampos son campos de tamaño de palabra sin caja en el Bookconstructor.

Tipos de datos algebraicos

Debido a esta necesidad de borrar el constructor, a newtypesolo funciona cuando se ajusta un tipo de datos con un solo constructor . No hay noción de nuevos tipos "algebraicos". Es decir, no puede escribir un equivalente de nuevo tipo de, digamos,

data Maybe a = Nothing
             | Just a

ya que tiene más de un constructor. Tampoco puedes escribir

newtype Book = Book Int Int

Rigor

El hecho de que el constructor se borre conduce a algunas diferencias muy sutiles en la rigidez entre datay newtype. En particular, dataintroduce un tipo que se "levanta", lo que significa, esencialmente, que tiene una forma adicional de evaluar a un valor inferior. Como no hay un constructor adicional en tiempo de ejecución con newtype, esta propiedad no se cumple.

Ese puntero extra en el Bookque (,)el constructor nos permite poner un valor inferior en.

Como resultado, newtypey datatienen propiedades de rigidez ligeramente diferentes, como se explica en el artículo wiki de Haskell .

Unboxing

No tiene sentido desempaquetar los componentes de a newtype, ya que no hay constructor. Si bien es perfectamente razonable escribir:

data T = T {-# UNPACK #-}!Int

produciendo un objeto de tiempo de ejecución con un Tconstructor y un Int#componente. Solo te desnudas Intcon newtype.


referencias :

Don Stewart
fuente
2
Todavía no creo que extrañaría algo si no hubiera "newtype" en Haskell. Las diferencias sutiles añaden complejidad a la lengua que no parece que merezca la pena para mí ...
martingw
14
La diferencia es muy útil por razones de rendimiento. Dado que los constructores de nuevos tipos se borran en el momento de la compilación, no imponen la penalización de rendimiento de tiempo de ejecución que hace un constructor de datos. Pero aún así le brindan todos los beneficios de un tipo completamente distinto y cualquier abstracción que desee asociar con él. Por ejemplo, hay dos formas diferentes en que el tipo de datos de la lista puede formar una mónada. Uno está integrado en el lenguaje, pero si desea utilizar el otro, un nuevo tipo sería el camino a seguir.
mightybyte
¡Gran explicación! Lo que no entiendo es que si newtypese borra después de la compilación y el tiempo de ejecución usa la misma representación para los tipos antiguos y nuevos, ¿cómo podemos definir instancias para el tipo antiguo y el nuevo? ¿Cómo puede entender el tiempo de ejecución qué instancia usar?
Damluar
3
@damluar Todos los tipos se borran en tiempo de ejecución, todos se resuelven por completo en el momento de la compilación y, durante la compilación, newtypeobviamente todavía no se borran.
punto
3
@damlaur Una vez tuve la misma pregunta que tú. Cuando las personas dicen que los tipos se borran, omiten mencionar que una cosa NO SE borra, que es una palabra de memoria que se usa para las búsquedas en el diccionario para decidir qué método de instancia usar para un dato determinado. La gente argumenta que esta palabra no es un "tipo", lo cual creo que depende de su perspectiva, pero ahí lo tiene.
Gabriel L.