Quelle est la différence lorsque j'écris ceci?
data Book = Book Int Int
contre
newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
haskell
types
type-systems
newtype
ewggwegw
la source
la source
newtype Book = Book Int Int
n'est pas valide. Vous pouvez cependant avoirnewtype Book = Book (Int, Int)
comme indiqué par les dons ci-dessous.Réponses:
Excellente question!
Il existe plusieurs différences clés.
Représentation
newtype
garantit que vos données auront exactement la même représentation au moment de l'exécution, que le type que vous encapsulez.data
déclare une toute nouvelle structure de données au moment de l'exécution.Donc, le point clé ici est que la construction pour le
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 que a
(Int,Int)
, puisque leBook
constructeur est effacé.data Book = Book (Int, Int)
Possède un
Book
constructeur supplémentaire non présent dans lenewtype
.data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int
Pas de pointeurs! Les deux
Int
champs sont des champs de la taille d'un mot sans boîte dans leBook
constructeur.Types de données algébriques
En raison de ce besoin d'effacer le constructeur, a
newtype
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 newtype de, disons,car il a plus d'un constructeur. Tu ne peux pas non plus écrire
Rigueur
Le fait que le constructeur soit effacé conduit à des différences très subtiles de rigueur entre
data
etnewtype
. En particulier,data
introduit un type qui est "soulevé", 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 au moment de l'exécution avecnewtype
, cette propriété ne tient pas.Ce pointeur supplémentaire dans le
Book
au(,)
constructeur nous permet de mettre une valeur inférieure à.En conséquence,
newtype
etdata
ont des propriétés de rigueur légèrement différentes, comme expliqué dans l'article du wiki Haskell .Déballage
Cela n'a pas de sens de déballer les composants de a
newtype
, car il n'y a pas de constructeur. S'il est parfaitement raisonnable d'écrire:produisant un objet d'exécution avec un
T
constructeur et unInt#
composant. Vous obtenez juste un nuInt
avecnewtype
.Références :
la source
newtype
est effacé après la compilation et que l'exécution utilise la même représentation pour les anciens et les nouveaux types, comment pouvons-nous encore être en mesure de définir des instances pour l'ancien et le nouveau type? Comment le runtime peut-il comprendre quelle instance utiliser?newtype
évidemment pas encore effacés.