Различные типы в функции суммы

Я новичок в Хаскеле, так что это может быть глупым вопросом. Я читаю книгу, где написано :type sum должен показать sum :: (Num a) => [a] -> a, Вместо этого сообщение sum :: (Num a, Foldable t) => t a -> a, Как я видел в https://www.haskell.org/hoogle/?hoogle=Sum эта разница обусловлена ​​- я думаю - существованием двух разных функций суммы. Может быть, это что-то вроде полиморфизма в Java, я только начинаю и понятия не имею, как работает Haskell.

Итак, мои вопросы: как я могу использовать функцию суммы, какой тип sum :: (Num a) => [a] -> a вместо другого? Не могли бы вы объяснить мне, что здесь происходит?

1 ответ

Решение

Как я видел в https://www.haskell.org/hoogle/?hoogle=Sum эта разница обусловлена ​​- я думаю - существованием двух разных функций суммы. Может быть, это что-то вроде полиморфизма в Java

Это действительно полиморфизм, хотя и не таким образом (см. PS в конце этого ответа). Обратите внимание, что...

sum :: (Num a) => [a] -> a

... уже полиморфна в типе суммируемых чисел, поэтому она будет работать, например, со списками Integer и списки Double, Разница между этим и...

sum :: (Num a, Foldable t) => t a -> a

... это sum Также полиморфен в типе контейнера:

GHCi> -- +t makes GHCi print the types automatically.
GHCi> :set +t
GHCi> sum [1 :: Integer, 2, 3]
6
it :: Integer
GHCi> sum [1 :: Double, 2, 3]
6.0
it :: Double
GHCi> import qualified Data.Set as S
GHCi> :t S.fromList
S.fromList :: Ord a => [a] -> S.Set a
GHCi> sum (S.fromList [1 :: Double, 2, 3])
6.0
it :: Double

Для типа контейнера, который будет использоваться с sum, он должен иметь экземпляр Foldable класс, который охватывает функции, которые, как sum, может быть выражено как сведение контейнера в список, а затем как-то сворачивать его.

PS: ваша книга говорит нечто иное, чем то, что вы видели, потому что до недавнего времени sum функция в Prelude имела менее общий тип, относящийся к списку, и ваша книга предшествует изменению. Наличие двух разных функций называется sumдаже если один из них носит более общий характер, чем другой, приведет к конфликту имен (по той же причине я импортировал Data.Set модуль квалифицирован в примере выше - это хорошая идея, потому что он определяет несколько функций, таких как map это столкновение с функциями Prelude, и квалифицируя их, скажем, S.map избегает любых проблем).

Другие вопросы по тегам