многопараметрический newtype, фальсифицированный с помощью кортежа? - PullRequest
10 голосов
/ 07 августа 2011

Это тупой вопрос, который меня немного беспокоит.Почему я не могу написать новый тип с несколькими параметрами,

newtype A = A Int Int

, в то время как версия кортежа просто прекрасна?

newtype A = A (Int, Int)

первая намного лучше в таких вещах, как сопоставление с образцом.

Ответы [ 2 ]

11 голосов
/ 07 августа 2011

newtype A = A Int создает тип, изоморфный Int. То есть он ведет себя так же, как Int w.r.t. например bottom, но под другим именем.

Это отличается от data A = A Int, который создает поднятый тип, который ведет себя не так, как Int. Есть еще одно добавленное значение, которого нет в Int: A undefined (что отличается от undefined::A).

Теперь newtype A = A (Int, Int) создает тип, изоморфный (Int, Int). Кстати, именно это и делает data A = A Int Int.

Итак, если мы признаем newtype A = A Int Int эквивалентным newtype A = A (Int, Int), что мы имеем? newtype A = A Int Int эквивалентно newtype A = A (Int, Int), что эквивалентно data A = A Int Int.

newtype A = A Int Int эквивалентно data A = A Int Int (поэтому newtype в данном случае избыточно), , но

newtype A = A Int равно , а не эквивалентно data A = A Int (в этом весь смысл наличия newtype на первом месте).

Итак, мы должны сделать вывод, что newtype A = A Int Int эквивалентно newtype A = A (Int, Int) создает избыточность и несогласованность, и нам лучше не допустить этого.

Вероятно, нет никакого способа придать newtype A = A Int Int какое-либо другое значение, свободное от этих несоответствий (иначе, я полагаю, оно будет найдено и использовано;)

7 голосов
/ 07 августа 2011

Поскольку 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 и узнайте!

...