В чем разница, когда я пишу это?
data Book = Book Int Int
newtype Book = Book(Int, Int) -- "Book Int Int" is syntactically invalid
В чем разница, когда я пишу это?
data Book = Book Int Int
newtype Book = Book(Int, Int) -- "Book Int Int" is syntactically invalid
Отличный вопрос!
Существует несколько ключевых отличий.
Представление
newtype гарантирует, что ваши данные будут иметь точно такое же представление во время выполнения, как и тип, который вы заверяете.data объявляет о новой структуре данных во время выполнения.Итак, ключевым моментом здесь является то, что конструкция для newtype гарантируется, что будет стерта во время компиляции.
Примеры:
data Book = Book Int Int 
newtype Book = Book (Int, Int) 
Обратите внимание, что он имеет точно такое же представление, как и (Int,Int), поскольку конструктор Book стирается.
data Book = Book (Int, Int) 
Имеется дополнительный конструктор Book, отсутствующий в newtype.
data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int 
Нет указателей! Два поля Int представляют собой незанятые поля размера слова в конструкторе Book.
Алгебраические типы данных
Из-за необходимости стирать конструктор, newtype работает только при обертке типа данных с помощью одного конструктора. Нет понятия "алгебраических" новых типов. То есть вы не можете написать эквивалент newtype, скажем,
data Maybe a = Nothing
| Just a
поскольку он содержит более одного конструктора. Вы также не можете написать
newtype Book = Book Int Int
Строгость
Тот факт, что конструктор стирается, приводит к некоторым очень тонким различиям в строгости между data и newtype. В частности, data вводит тип, который "снят", что означает, по существу, что у него есть дополнительный способ оценить нижнее значение. Поскольку во время выполнения с newtype нет дополнительного конструктора, это свойство не выполняется.
Этот дополнительный указатель в конструкторе Book to (,) позволяет нам установить нижнее значение.
В результате newtype и data имеют несколько иные свойства строгости, поскольку объясняется в статье Wiki Haskell.
Распаковка
Не имеет смысла распаковывать компоненты newtype, так как нет конструктора. Хотя вполне разумно писать:
data T = T {-# UNPACK #-}!Int
дает объект времени выполнения с конструктором T и компонентом Int#. Вы получите только Int с newtype.
Литература: