Поскольку newtype
, грубо говоря, работает как type
во время выполнения и как data
во время компиляции. Каждое определение data
добавляет дополнительный уровень косвенности - что при нормальных обстоятельствах означает другое отдельное место, где что-то может быть оставлено как громоотвод - вокруг значений, которые оно содержит, тогда как newtype
- нет. «Конструктор» на newtype
- это просто иллюзия.
Все, что объединяет несколько значений в одно или дает выбор между несколькими случаями, обязательно вводит слой косвенности, чтобы выразить это, поэтому логическая интерпретация newtype A = A Int Int
будет представлять собой два несвязанных значения Int
, в которых ничего не содержится их вместе ". Разница в случае newtype A = A (Int, Int)
заключается в том, что сам кортеж добавляет дополнительный уровень косвенности.
Сравните это с data A = A Int Int
против data A = A (Int, Int)
. Первый добавляет один слой (конструктор A
) вокруг двух Int
s, а второй добавляет тот же слой вокруг кортежа, который сам добавляет слой вокруг Int
s.
Каждый слой косвенности также обычно добавляет место, где что-то может быть ⊥, поэтому рассмотрим возможные случаи для каждой формы, где? обозначает не нижнее значение:
Для newtype A = A (Int, Int)
: ⊥
, (⊥, ?)
, (?, ⊥)
, (?, ?)
Для data A = A Int Int
: ⊥
, A ⊥ ?
, A ? ⊥
, A ? ?
Для data A = A (Int, Int)
: ⊥
, A ⊥
, A (⊥, ?)
, A (?, ⊥)
, A (?, ?)
Как видно из вышесказанного, первые два эквивалентны.
В заключение отметим забавную демонстрацию того, как newtype
отличается от data
. Рассмотрим эти определения:
data D = D D deriving Show
newtype N = N N deriving Show
Какие возможные значения, включая все возможные, есть у каждого из них? И как вы думаете, какие два значения будут ниже?
d = let (D x) = undefined in show x
n = let (N x) = undefined in show x
Загрузите их в GHC и узнайте!