Unterschied zwischen "Daten" und "Newtype" in Haskell

191

Was ist der Unterschied, wenn ich das schreibe?

data Book = Book Int Int

gegen

newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
ewggwegw
quelle
Sie sollten etwas suchen, diese Frage wurde bereits beantwortet. stackoverflow.com/questions/2649305/…
tehman
Im Zusammenhang mit stackoverflow.com/questions/2649305/…
Don Stewart
Ebenfalls verwandt: Verwendet für Newtype: stackoverflow.com/questions/991467/…
Don Stewart
25
Beachten Sie, dass dies newtype Book = Book Int Intnicht gültig ist. Sie können jedoch newtype Book = Book (Int, Int)wie von Dons unten angegeben haben.
Edward KMETT

Antworten:

241

Gute Frage!

Es gibt mehrere wesentliche Unterschiede.

Darstellung

  • A newtypegarantiert, dass Ihre Daten zur Laufzeit genau dieselbe Darstellung haben wie der Typ, den Sie umbrechen.
  • Während datadeklariert zur Laufzeit eine brandneue Datenstruktur.

Der entscheidende Punkt hierbei ist also, dass das Konstrukt für das newtypebeim Kompilieren garantiert gelöscht wird.

Beispiele:

  • data Book = Book Int Int

Daten

  • newtype Book = Book (Int, Int)

neuer Typ

Beachten Sie, dass es genau die gleiche Darstellung wie a hat (Int,Int), da der BookKonstruktor gelöscht wird.

  • data Book = Book (Int, Int)

Datentupel

Hat einen zusätzlichen BookKonstruktor nicht in der newtype.

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

Geben Sie hier die Bildbeschreibung ein

Keine Hinweise! Die beiden IntFelder sind wortgroße Felder im BookKonstruktor.

Algebraische Datentypen

Aufgrund dieser Notwendigkeit, den Konstruktor zu löschen, newtypefunktioniert a nur, wenn ein Datentyp mit einem einzelnen Konstruktor umbrochen wird . Es gibt keine Vorstellung von "algebraischen" neuen Typen. Das heißt, Sie können kein Newtype-Äquivalent von beispielsweise schreiben.

data Maybe a = Nothing
             | Just a

da es mehr als einen Konstruktor hat. Du kannst auch nicht schreiben

newtype Book = Book Int Int

Strenge

Die Tatsache, dass der Konstruktor gelöscht wird, führt zu einigen sehr subtilen Unterschieden in der Strenge zwischen dataund newtype. Insbesondere wird dataein Typ eingeführt, der "angehoben" wird, was im Wesentlichen bedeutet, dass er eine zusätzliche Möglichkeit bietet, einen unteren Wert zu ermitteln. Da es zur Laufzeit mit keinen zusätzlichen Konstruktor gibt newtype, gilt diese Eigenschaft nicht.

Mit diesem zusätzlichen Zeiger im Bookto- (,)Konstruktor können wir einen unteren Wert eingeben.

Infolgedessen newtypeund datahaben leicht unterschiedliche Strengeigenschaften, wie im Haskell-Wiki-Artikel erläutert .

Unboxing

Es ist nicht sinnvoll, die Komponenten von a zu entpacken newtype, da es keinen Konstruktor gibt. Während es völlig vernünftig ist zu schreiben:

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

Ausgeben eines Laufzeitobjekts mit einem TKonstruktor und einer Int#Komponente. Sie bekommen nur eine nackte Intmit newtype.


Referenzen :

Don Stewart
quelle
2
Ich glaube immer noch nicht, dass ich etwas verpassen würde, wenn es in Haskell keinen "Newtype" gäbe. Die subtilen Unterschiede erhöhen die Komplexität der Sprache, die mir nicht lohnenswert erscheint ...
Martingw
14
Der Unterschied ist aus Leistungsgründen sehr nützlich. Da Newtype-Konstruktoren zur Kompilierungszeit gelöscht werden, verursachen sie nicht die Laufzeitleistungseinbußen, die ein Datenkonstruktor verursacht. Aber sie bieten Ihnen immer noch alle Vorteile eines völlig unterschiedlichen Typs und aller Abstraktionen, die Sie damit verbinden möchten. Beispielsweise gibt es zwei verschiedene Möglichkeiten, wie der Listendatentyp eine Monade bilden kann. Einer ist in die Sprache integriert, aber wenn Sie den anderen verwenden möchten, ist ein neuer Typ der richtige Weg.
mächtig Byte
Tolle Erklärung! Was ich nicht verstehe ist, wenn newtypenach dem Kompilieren gelöscht wird und die Laufzeit dieselbe Darstellung für alte und neue Typen verwendet. Wie können wir dann noch Instanzen für alte und neue Typen definieren? Wie kann die Laufzeit verstehen, welche Instanz verwendet werden soll?
Damluar
3
@damluar Alle Typen werden zur Laufzeit gelöscht, sie werden alle zur Kompilierungszeit vollständig aufgelöst und während der Kompilierung newtypewerden sie offensichtlich noch nicht gelöscht.
Semikolon
3
@ Damlaur Ich hatte einmal die gleiche Frage wie Sie. Wenn Leute sagen, dass die Typen gelöscht werden, lassen sie es aus, zu erwähnen, dass eine Sache NICHT gelöscht wird. Dies ist ein Speicherwort, das für Wörterbuchsuchen verwendet wird, um zu entscheiden, welche Instanzmethode für ein bestimmtes Datenelement verwendet werden soll. Die Leute argumentieren, dass dieses Wort kein "Typ" ist, was meiner Meinung nach von Ihrer Perspektive abhängt, aber los geht's.
Gabriel L.