Quelle est la différence quand j’écris ceci?
data Book = Book Int Int newtype Book = Book(Int, Int) -- "Book Int Int" is syntactically invalid
Bonne question!
Il y a 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éclarent une nouvelle structure de données lors de l’exécution. Le point clé ici est que la construction du nouveau type 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 de 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 la taille d’un mot sans boîte dans le constructeur Book
.
Types de données algébriques
En raison de la nécessité d’effacer le constructeur, un nouveau type ne fonctionne que lors de l’encapsulation d’un type de données avec un seul constructeur . Il n’y a pas de notion de newtypes “algébriques”. Autrement dit, vous ne pouvez pas écrire un équivalent de newtype de, 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é entraîne des différences de subtilité très subtiles entre les data
et le newtype
. En particulier, les data
introduisent un type qui est “levé”, ce qui signifie essentiellement qu’il a un moyen supplémentaire d’évaluer une valeur inférieure. Comme il n’y a pas de constructeur supplémentaire à l’exécution avec newtype
, cette propriété ne tient pas.
Ce pointeur supplémentaire dans le constructeur Book
to (,)
nous permet de placer une valeur inférieure dans.
En conséquence, newtype
et data
ont des propriétés de sévérité légèrement différentes, comme expliqué dans l’article du wiki Haskell .
Déballage
Cela n’a aucun sens de déballer les composants d’un newtype
, car il n’y a pas de constructeur. Bien qu’il soit parfaitement raisonnable d’écrire:
data T = T {-# UNPACK #-}!Int
fournissant un object d’exécution avec un constructeur T
et un composant Int#
. Vous venez d’obtenir un Int
nu avec newtype
.
Références :