Haskell, различия между sum (x, y) и sum (x, y, z)

#haskell #sum

#haskell #сумма

Вопрос:

Меня смущают различия между sum (x,y) и sum(x,y,z) . Сигнатура типа sum , похоже, (Foldable t, Num a) => t a -> a . Что я получаю, так это то, что он принимает foldable t и класс типов Num a . Sum (x, y) всегда выводит y, а sum (x, y, z) выдает ошибку:

  "Could not deduce (Foldable ((,,) Integer Integer))
        arising from a use of `sum'"
  

Итак, почему sum (x, y) может выводить что-то по сравнению с sum (x, y, z)

Комментарии:

1. но чтобы ответить на вопрос Haskell, это потому, что пары определяются как экземпляр Foldable , а тройки — нет. На самом деле это не имеет большого смысла для меня (как и экземпляр для pairs, который просто игнорирует первый элемент), но так оно и есть.

2. Вы хотите попробовать sum [1,2] и sum [1,2,3] .

3. Эй, Робин, да, это конкретно проблема haskell. Большое вам спасибо за редактирование тегов. Впервые использую stack overflow.

4. Семантика n -кортежа — это семантика единственного значения, хранящегося в контексте n-1 других значений. Что-то с Foldable экземпляром должно иметь вид * -> * , что в случае типов продуктов всегда означает, что первые n-1 значения эффективно игнорируются. Functor и Foldable оба делают это последовательно: fmap ( 1) ('a', 3) == ('a', 4) , в то время как sum ('a', 3) == 3 . (Каждая Foldable функция делает немногим больше, чем извлекает значение из своего контекста.) Для 2-х кортежей экземпляры предназначены для (,) a , а не (a, b) ; для 3-х кортежей они были бы для (,,) a b not (a, b, c) ; и т.д.

5. @chepner Это верно с формальной точки зрения, но как часто люди на самом деле используют подобные кортежи? ( Writer и Control.Comonad.Env в сторону)

Ответ №1:

Как в Python, так и в Haskell, (x,y,z) является кортежем, тогда как [x,y,z] это список. Однако, в то время как списки в значительной степени одинаковы на обоих языках, кортежи различны: кортежи Python похожи на списки Python, тогда как в Haskell кортежи — это совершенно другая концепция (РЕДАКТИРОВАТЬ: я был неправ); в Haskell кортежи похожи на записи без имен полей (например, (1, "foo", 'b') типа (Int, String, Char) ). Таким образом, в Haskell вы не можете суммировать кортежи вообще (поскольку вы не можете гарантировать, что каждое «поле» имеет один и тот же тип), что в основном и Could not deduce Foldable означает. Однако Foldable экземпляр в прелюдии действительно существует для двух кортежей! Однако, как прокомментировал @RobinZigmond, это работает не так, как вы могли бы ожидать: поскольку он не может гарантировать, что оба поля одного типа, он просто полностью игнорирует первый элемент:

 Prelude> sum (1,2)
2
  

Комментарии:

1. «списки практически одинаковы на обоих языках» — я бы оспорил это. Списки Haskell являются настоящими «связанными списками», тогда как я почти уверен, что «списки» Python на самом деле являются массивами. (И, следовательно, более эффективные — списки Haskell довольно неэффективны для многих вещей, для которых вы использовали бы списки в Python.)

2. @RobinZigmond Верно. Я имел в виду, что в обоих языках списки используются для одной и той же концепции (списка значений), тогда как кортежи — нет.

3. @bradrn С другой стороны, кортежи используются для одной и той же концепции, списки разные, однако большинство людей используют их одинаково: однородный список элементов.

4. «это не работает должным образом» это работает абсолютно правильно, то, как это работает, просто не совсем то, что ожидает большинство людей.

5. Существует еще один способ, с помощью которого кортежи Haskell и Python ближе друг к другу, чем списки Haskell и Python: кортежи неизменяемы на обоих языках, тогда как списки Python изменяемы, а списки Haskell неизменяемы.