Haskell - fmap fmap не работает

Я использую GHCi (версия 6.12.3), чтобы немного поиграть с Haskell. Недавно я прочитал о функторах и аппликативных функторах, подумал, что нельзя реализовать что-то похожее на <*> аппликативных функторов только с использованием примитивов функтора. После некоторого размышления я придумал fmap fmap, у которого был бы (почти) идеальный тип

Functor f => f (a -> b) -> f (f a -> f b) или больше в целом

(Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b)

Я пытался

let q = fmap fmap

Я получил следующую ошибку

<interactive>:1:8:
    Ambiguous type variable `f1' in the constraint:
      `Functor f1' arising from a use of `fmap' at <interactive>:1:8-16
    Probable fix: add a type signature that fixes these type variable(s)

<interactive>:1:13:
    Ambiguous type variable `f' in the constraint:
      `Functor f' arising from a use of `fmap' at <interactive>:1:13-16
    Probable fix: add a type signature that fixes these type variable(s)

Написание приведенной выше подписи типа, как было предложено, не помогло. Самое безумное, что когда я набрал :t fmap fmap, я получил эквивалентный тип, как указано выше.

Что я делаю неправильно? Почему fmap fmap выдает ошибку типа, хотя GHCi находит для нее тип?


person Mafi    schedule 29.04.2011    source источник


Ответы (2)


Похоже, вы столкнулись с ограничением мономорфизма.

Попытка вашего примера в GHCi с -XNoMonomorphismRestriction дает ожидаемый результат.

Вы также можете подорвать это, написав let f x = fmap fmap $ x. Ограничение мономорфизма применяется только к определениям верхнего уровня, которые «выглядят как» значения, то есть f = something, поэтому введение явного аргумента приводит к тому, что оно больше не применяется. Это также не применялось бы, если бы это не было на верхнем уровне (например, в предложении where). Для получения более подробной информации см. ссылку.

person hammar    schedule 29.04.2011
comment
Кажется, это ограничение мономорфизма, потому что работает душа. Спасибо. Но почему это не сработало, когда я указал тип? - person Mafi; 30.04.2011

Я не могу комментировать везде, поэтому я опубликую ответ. Как упоминалось ранее, ошибка, которую вы получаете, связана с ограничением мономорфизма. Исправление подписи типа для любого из двух, указанных в исходном вопросе, действительно делает ghci счастливым, как вы и надеялись, может быть, вы просто немного ошиблись в синтаксисе?

Prelude> let q :: (Functor f) => f (a -> b) -> f (f a -> f b); q = fmap fmap
Prelude> :t q
q :: (Functor f) => f (a -> b) -> f (f a -> f b)

Prelude> let q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b); q = fmap fmap
Prelude> :t q
q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b)
person monk    schedule 30.04.2011