Какая разница, когда я это пишу?
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и, очевидно, еще не стираются во время компиляции .