Różnica między „data” a „newtype” w Haskell

191

Jaka jest różnica, kiedy to piszę?

data Book = Book Int Int

przeciw

newtype Book = Book (Int, Int) -- "Book Int Int" is syntactically invalid
ewggwegw
źródło
Powinieneś trochę poszukać, na to pytanie już udzielono odpowiedzi. stackoverflow.com/questions/2649305/…
tehman
Związane z stackoverflow.com/questions/2649305/…
Don Stewart
Powiązane również: zastosowania dla nowego typu: stackoverflow.com/questions/991467/…
Don Stewart
25
Pamiętaj, że newtype Book = Book Int Intto nie jest poprawne. Możesz jednak mieć, newtype Book = Book (Int, Int)jak zauważyli donowie poniżej.
Edward KMETT

Odpowiedzi:

241

Świetne pytanie!

Istnieje kilka kluczowych różnic.

Reprezentacja

  • A newtypegwarantuje, że dane będą miały dokładnie taką samą reprezentację w czasie wykonywania, jak rodzaj zawinąć.
  • Podczas datadeklaruje zupełnie nową strukturę danych w czasie wykonywania.

Kluczową kwestią jest tutaj to, że konstrukcja dla newtype gwarantowana jest wymazana w czasie kompilacji.

Przykłady:

  • data Book = Book Int Int

dane

  • newtype Book = Book (Int, Int)

nowy typ

Zauważ, że ma dokładnie taką samą reprezentację jak a (Int,Int), ponieważ Bookkonstruktor jest kasowany.

  • data Book = Book (Int, Int)

krotka danych

Ma dodatkowy Bookkonstruktor nieobecny w newtype.

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

wprowadź opis zdjęcia tutaj

Brak wskazówek! Te dwa Intpola są w konstruktorze rozpakowanymi polami wielkości słowa Book.

Algebraiczne typy danych

Z powodu tej potrzeby skasowania konstruktora: newtype działa tylko podczas owijania typu danych jednym konstruktorem . Nie ma pojęcia o „typach algebraicznych”. Oznacza to, że nie można napisać nowego odpowiednika, powiedzmy,

data Maybe a = Nothing
             | Just a

ponieważ ma więcej niż jednego konstruktora. Nie możesz też pisać

newtype Book = Book Int Int

Ścisłość

Usunięcie konstruktora prowadzi do bardzo subtelnych różnic w ścisłości między nimi data i newtype. W szczególności datawprowadza typ, który jest „podnoszony”, co w istocie oznacza, że ​​ma on dodatkowy sposób oceny do dolnej wartości. Ponieważ w środowisku wykonawczym nie ma dodatkowego konstruktoranewtype , ta właściwość nie zachowuje się.

Ten dodatkowy wskaźnik w Book(,) konstruktorze do pozwala nam wstawić dolną wartość.

W rezultacie newtypeidata mają nieco inne właściwości surowości, jak wyjaśniono w artykule Haskell wiki .

Rozpakowanie

Rozpakowywanie składników a nie ma sensu newtype, ponieważ nie ma konstruktora. Chociaż napisanie:

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

zwracanie obiektu wykonawczego za pomocą Tkonstruktora i Int#komponentu. Wystarczy dostać nagie Intznewtype .


Referencje :

Don Stewart
źródło
2
Nadal nie sądzę, że coś przegapiłbym, gdyby w Haskell nie było „nowego typu”. Subtelne różnice zwiększają złożoność języka, który wydaje mi się
niegodny
14
Różnica jest bardzo przydatna ze względu na wydajność. Ponieważ konstruktory nowego typu są usuwane w czasie kompilacji, nie nakładają one ujemnego wpływu na wydajność środowiska wykonawczego, jakie ma konstruktor danych. Ale nadal dają ci wszystkie zalety zupełnie odrębnego typu i wszelkie abstrakcje, które chcesz z nim skojarzyć. Na przykład istnieją dwa różne sposoby, w jaki typ danych listy może tworzyć monadę. Jeden jest wbudowany w język, ale jeśli chcesz użyć drugiego, najlepszym rozwiązaniem będzie nowy typ.
mightybyte
Świetne wyjaśnienie! Nie rozumiem, że jeśli newtypejest usuwany po kompilacji, a środowisko wykonawcze używa tej samej reprezentacji dla starych i nowych typów, w jaki sposób możemy nadal być w stanie zdefiniować wystąpienia zarówno dla starego, jak i nowego typu? Jak środowisko wykonawcze może zrozumieć, której instancji użyć?
damluar
3
@damluar Wszystkie typy są kasowane w czasie wykonywania, wszystkie są w pełni rozwiązywane w czasie kompilacji, a podczas kompilacji newtypeoczywiście nie są jeszcze kasowane.
średnik
3
@damlaur Miałem kiedyś to samo pytanie co ty. Kiedy ludzie mówią, że typy są usuwane, pomijają wspomnienie, że jedna rzecz NIE JEST usuwana, to jest słowo pamięci, które jest używane do wyszukiwania w słowniku, aby zdecydować, jakiej metody instancji użyć dla danego fragmentu danych. Ludzie twierdzą, że to słowo nie jest „typem”, co myślę, że zależy od twojej perspektywy, ale proszę bardzo.
Gabriel L.