Почему выражение `foldr (mappend . Sum) 1 [2]` проверяет тип?

Если я бета-уменьшу следующее выражение:

  foldr (mappend . Sum) 1 [2]
= (mappend . Sum) 2 (foldr (mappend . Sum) 1 [])
= (mappend . Sum) 2 1
= mappend (Sum 2) 1
...

Глядя на тип:

// mappend (<>) :: Monoid a => a -> a -> a

Мы видим, что в последней строке ошибка типа, потому что константа 1 должна принадлежать классу Monoid (а это не так).

Однако ghci не жалуется.

Почему этот тип выражения проверяет?

Крайне важно знать тип ваших терминов, два числовых литерала не одного типа: foldr ((<>) . Sum) (1 :: Sum Int) [2 :: Int]

Iceland_jack 20.11.2022 23:03

Да, конечно. Для меня оба числовых литерала имели разные типы.

F. Zer 20.11.2022 23:07
[JS за 1 час] - 9. Асинхронный
[JS за 1 час] - 9. Асинхронный
JavaScript является однопоточным, то есть он может обрабатывать только одну задачу за раз. Для обработки длительных задач, таких как сетевые запросы,...
Топ-10 компаний-разработчиков PHP
Топ-10 компаний-разработчиков PHP
Если вы ищете надежных разработчиков PHP рядом с вами, вот список лучших компаний по разработке PHP.
Скраппинг поиска Apple App Store с помощью Python
Скраппинг поиска Apple App Store с помощью Python
📌Примечание: В этой статье я покажу вам, как скрапировать поиск Apple App Store и получить точно такой же результат, как на Apple iMac, потому что...
Редкие достижения на Github ✨
Редкие достижения на Github ✨
Редкая коллекция доступна в профиле на GitHub ✨
Подъем в javascript
Подъем в javascript
Hoisting - это поведение в JavaScript, при котором переменные и объявления функций автоматически "перемещаются" в верхнюю часть соответствующих...
Улучшение генерации файлов Angular
Улучшение генерации файлов Angular
Angular - это фреймворк. Вы можете создать практически любое приложение без использования сторонних библиотек.
2
2
113
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Краткий ответ: 1 интерпретируется как Sum a, поэтому тип вашей папки:

foldr (mappend . Sum) 1 [2] :: Num a => Sum a

Где 2 имеет тип a, а 1 имеет тип Sum a.

Sum a является экземпляром Num, если a является экземпляром Num, действительно, исходный код говорит [src]:

newtype Sum a = Sum { getSum :: a }
        deriving ( Eq       -- ^ @since 2.01
                 , Ord      -- ^ @since 2.01
                 , Read     -- ^ @since 2.01
                 , Show     -- ^ @since 2.01
                 , Bounded  -- ^ @since 2.01
                 , Generic  -- ^ @since 4.7.0.0
                 , Generic1 -- ^ @since 4.7.0.0
                 , Num      -- ^ @since 4.7.0.0
                 )

Таким образом, это означает, что если вы пишете целочисленный литерал, такой как 1, он может быть построен как Sum a для любого a, являющегося экземпляром Num, поэтому 1 :: Sum Integer есть Sum 1.

Таким образом, это означает, что 1 в вашем foldr имеет тип Sum a, и поэтому, например:

   mappend (Sum 2 :: Sum Integer) (1 :: Sum Integer)
-> Sum (2 + 1)
-> Sum 3

Спасибо за прекрасный ответ, но я чего-то не понимаю. В моем примере 1 является синтаксическим сахаром для fromInteger 1, так что это настоящая причина, по которой выражение foldr (mappend . Sum) 1 проверяет тип. Это правильно ?

F. Zer 21.11.2022 23:00

@F.Zer: да, верно. Для каждого литерала int в основном ставится fromInteger впереди. Но это для литерала, а не для целочисленного выражения. Так что 1 + (2 :: Int) будет Int, а не чем-то вроде fromIntegral (1+2 :: Int) и т. д.

Willem Van Onsem 21.11.2022 23:07
Ответ принят как подходящий

В документации для типа Sum вы найдете этот контрольный пример:

Num a => Num (Sum a)

(что, конечно, имеет смысл в том, что он должен быть там - мало того, что Sum a "морально тот же тип", что и a, Sum в любом случае явно предназначен для использования только с числовыми типами).

Поскольку числовые литералы, такие как 1 в Haskell, могут быть любого типа, являющегося экземпляром класса Num, в mappend (Sum 2) 1 нет ошибки типа, потому что компилятор автоматически преобразует его в mappend (Sum 2) (Sum 1). (Поскольку в этом экземпляре Num для Sum a fromInteger 1 будет Sum 1.)

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