Какая разница, когда я это пишу?
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 Book = Book Int Int
это недействительно. Однако вы можете сделать это, newtype Book = Book (Int, Int)
как указано ниже.
Ответы:
Отличный вопрос!
Есть несколько ключевых отличий.
Представление
newtype
гарантирует, что ваши данные будут иметь точно такое же представление во время выполнения, что и тип, который вы переносите.data
объявляет новую структуру данных во время выполнения.Таким образом, ключевым моментом здесь является то, что конструкция для newtype
класса гарантированно будет стерта во время компиляции.
Примеры:
data Book = Book Int Int
newtype Book = Book (Int, Int)
Обратите внимание на то, что он имеет то же представление, что и a (Int,Int)
, поскольку Book
конструктор удален.
data Book = Book (Int, Int)
Имеет дополнительный Book
конструктор, отсутствующий в newtype
.
data Book = Book {-# UNPACK #-}!Int {-# UNPACK #-}!Int
Никаких указателей! Эти два Int
поля представляют собой распакованные поля размером со слово в Book
конструкторе.
Алгебраические типы данных
Из-за необходимости стереть конструктор a newtype
работает только при обертке типа данных с помощью одного конструктора . Нет понятия «алгебраические» новые типы. То есть вы не можете написать эквивалент newtype, скажем,
data Maybe a = Nothing
| Just a
поскольку у него более одного конструктора. Вы также не можете писать
newtype Book = Book Int Int
Строгость
Тот факт, что конструктор удален, приводит к очень тонким различиям в строгости между data
и newtype
. В частности, data
вводится «приподнятый» тип, что по сути означает, что у него есть дополнительный способ вычисления нижнего значения. Поскольку во время выполнения с нет дополнительного конструктора newtype
, это свойство не сохраняется.
Это дополнительный указатель в Book
к (,)
конструктору позволяет поставить нижнее значение в.
В результате newtype
и data
имеют немного другие свойства строгости, как описано в статье вики-страницы Haskell .
Распаковка
Распаковывать компоненты a не имеет смысла newtype
, так как конструктора нет. Хотя вполне разумно написать:
data T = T {-# UNPACK #-}!Int
давая объект среды выполнения с T
конструктором и Int#
компонентом. Вы просто разобрались Int
с newtype
.
Ссылки :
newtype
стирается после компиляции, а среда выполнения использует одно и то же представление для старого и нового типов, как мы можем определять экземпляры как для старого, так и для нового типа? Как среда выполнения может понять, какой экземпляр использовать?
newtype
и, очевидно, еще не стираются во время компиляции .