我正在使用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
时,我得到了与上面相同的类型。
我做错了什么?尽管GHCi为它找到了一个类型,为什么fmap fmap
会给出类型错误?
答案 0 :(得分:7)
您似乎遇到了monomorphism restriction。
使用-XNoMonomorphismRestriction
在GHCi中尝试您的示例可以得到您期望的结果。
你也可以写let f x = fmap fmap $ x
来颠覆这一点。单态限制仅适用于“看起来像”值的顶级定义,即f = something
,因此引入显式参数会导致它不再适用。如果它不在顶层(例如在where
子句中),它也不适用。有关详细信息,请参阅链接。
答案 1 :(得分:1)
我无法在任何地方发表评论所以我会发布一个答案。如前所述,您收到的错误是由于单态限制造成的。将类型签名修复到原始问题中给出的两个中的任何一个确实让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)