В Haskell снятые продукты типа означают, что существует семантическое различие между (a, b, c) и (a, (b, c)).
Если бы все соответствия шаблона всех продуктов были всегда неопровержимы, то не было бы никакого различия, и (a, b, c) мог быть синтаксический сахар для (a, (b, c)).
Почему Haskell принимал решение снять продукты типа?
Одна из причин заключается в том, что реализация seq
для несмещенного произведения требует параллельных/перемежающихся вычислений, поскольку seq (a, b) True
должен быть True
тогда и только тогда, когда хотя бы одно из a
и b
не является нижним. Эта причина может показаться вам не слишком убедительной, в зависимости от того, как вы относитесь к seq
, но, конечно, полиморфный seq
по определению является частью Haskell...
Почему Haskell решил поднять типовые продукты?
Вы можете оправдать этот выбор дизайна, не прибегая к лени или опровержимым шаблонам. Сделан тот же выбор дизайна. ML из соображений поддержки полиморфизма. Рассмотрим
fst (x, y) = x
snd (x, y) = y
. Теперь, если (a, (b, c))
является синтаксическим сахаром для (a, b, c)
, довольно сложно понять, как специализироваться fst
и snd
, чтобы принять этот тип в качестве аргумента. Но
fst :: (a, (b, c)) -> a
snd :: (a, (b, c)) -> (b, c)
вполне разумны. Поскольку полиморфные функции, такие как fst
и snd
, невероятно полезны, и Haskell, и ML дают программисту возможность различать (a, (b, c))
и ((a, b), c)
из (a, b, c)
.
(Для людей, которые заботятся о затратах, структура типа также является разумным ориентиром для определения размера типа и количества косвенных обращений (загрузок), необходимых для получения его элементов. Некоторым программистам нужно или нужно знать о таких вещах и чтобы иметь некоторую небольшую степень контроля над ними.)
Вы можете произвести семантическую разницу, если хотите, в связи с классами типов.
(a, b, c)
и (a, (b, c))
могут создавать экземпляры классов по-разному. Подумайте только о
show (1, 2, 3)
и
show (1, (2, 3))
. Я бы счел нелогичным, чтобы оба они давали один и тот же результат.