Разница между `data` и` newtype` в Haskell

В чем разница, когда я пишу это?

data Book = Book Int Int

newtype Book = Book(Int, Int) -- "Book Int Int" is syntactically invalid

Ответ 1

Отличный вопрос!

Существует несколько ключевых отличий.

Представление

  • A newtype гарантирует, что ваши данные будут иметь точно такое же представление во время выполнения, как и тип, который вы заверяете.
  • Пока data объявляет о новой структуре данных во время выполнения.

Итак, ключевым моментом здесь является то, что конструкция для newtype гарантируется, что будет стерта во время компиляции.

Примеры:

  • data Book = Book Int Int

data

  • newtype Book = Book (Int, Int)

newtype

Обратите внимание, что он имеет точно такое же представление, как и (Int,Int), поскольку конструктор Book стирается.

  • data Book = Book (Int, Int)

data tuple

Имеется дополнительный конструктор Book, отсутствующий в newtype.

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

enter image description here

Нет указателей! Два поля 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.


Литература: