Quelle est la différence quand j'écris ceci?
data Book = Book Int Int
versus
newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
Grande question!
Il existe plusieurs différences clés.
Représentation
newtype
garantit que vos données auront exactement la même représentation à l'exécution, que le type que vous encapsulez.data
déclare une toute nouvelle structure de données lors de l'exécution.Donc, le point clé ici est que la construction de newtype
est garantie d'être effacée au moment de la compilation.
Exemples:
data Book = Book Int Int
newtype Book = Book (Int, Int)
Notez comment il a exactement la même représentation qu'un (Int,Int)
, Puisque le constructeur Book
est effacé.
data Book = Book (Int, Int)
A un constructeur Book
supplémentaire non présent dans le newtype
.
data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int
Pas de pointeurs! Les deux champs Int
sont des champs de taille Word non encadrés dans le constructeur Book
.
Types de données algébriques
En raison de ce besoin d'effacer le constructeur, un newtype
ne fonctionne que lors de l'encapsulation d'un type de données avec un seul constructeur . Il n'y a aucune notion de nouveaux types "algébriques". Autrement dit, vous ne pouvez pas écrire un équivalent de nouveau type, disons,
data Maybe a = Nothing
| Just a
car il a plus d'un constructeur. Vous ne pouvez pas non plus écrire
newtype Book = Book Int Int
Rigueur
Le fait que le constructeur soit effacé conduit à des différences de subtilité très subtiles entre data
et newtype
. En particulier, data
introduit un type qui est "levé", ce qui signifie, essentiellement, qu'il a un moyen supplémentaire d'évaluer une valeur inférieure. Puisqu'il n'y a pas de constructeur supplémentaire au moment de l'exécution avec newtype
, cette propriété ne tient pas.
Ce pointeur supplémentaire dans le constructeur Book
vers (,)
Nous permet de mettre une valeur inférieure dans.
Par conséquent, newtype
et data
ont des propriétés de rigueur légèrement différentes, comme expliqué dans l'article wiki de Haskell .
Déballage
Cela n'a pas de sens de déballer les composants d'un newtype
, car il n'y a pas de constructeur. S'il est parfaitement raisonnable d'écrire:
data T = T {-# UNPACK #-}!Int
produisant un objet d'exécution avec un constructeur T
et un composant Int#
. Vous obtenez simplement un Int
avec newtype
.
Références: