Почему `fmap sum Just` typecheck?

Мы знаем, что fmap есть fmap :: Functor f => (a -> b) -> f a -> f b, а sum - sum :: (Num a, Foldable t) => t a -> a, но приведенный ниже код путает меня.

> :t (fmap sum Just)
(fmap sum Just) :: Num b => b -> b
> fmap sum Just 3
3

почему?

Ответ 1

Я думаю, что здесь, вероятно, есть два путаных бита.

Первое, самое очевидное, заключается в том, что sum работает над Foldable вещами, а не только списками. Поэтому:

sum (Just 3) == 3

Второй экземпляр-функтор, который вы используете. Поскольку Just является функцией, так как это второй аргумент fmap, вы используете экземпляр чтения fmap, который здесь определен (https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Base.html#line-638) как просто (.).

Это выглядит странно, и, как будто он не должен проверять тип, потому что вы поставляете три аргумента в fmap, но на самом деле результат (fmap sum Just) является функцией:

Prelude> :t fmap sum Just
fmap sum Just :: Num b => b -> b  

Если мы заменим fmap на ., все станет немного более понятным.

Prelude> (.) sum Just 3
3

Prelude> (sum . Just) 3
3

То же, что и

sum (Just 3)