Différence entre `data` et` newtype` dans Haskell

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

  • Un newtype garantit que vos données auront exactement la même représentation à l’exécution, que le type que vous encapsulez.
  • Alors que les 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

Les données

  • newtype Book = Book (Int, Int)

nouveau genre

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)

tuple de données

A un constructeur de Book supplémentaire non présent dans le newtype .

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

entrer la description de l'image ici

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 :

  • “Newtype” sur le wiki Haskell
  • La réponse de Norman Ramsey à propos des propriétés de rigueur