5

我正在使用 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给出类型错误?

4

2 回答 2

7

看起来你遇到了单态限制

在 GHCi 中尝试您的示例-XNoMonomorphismRestriction给出了您预期的结果。

你也可以通过写作来颠覆这一点let f x = fmap fmap $ x。单态性限制仅适用于“看起来像”值的顶级定义,即f = something,因此引入显式参数会导致它不再适用。如果它不在顶层(例如在where子句中),它也将不适用。有关更多详细信息,请参阅链接。

于 2011-04-29T21:45:35.317 回答
1

我还不能到处发表评论,所以我会发布答案。如前所述,您收到的错误是由于单态限制。将类型签名修复为原始问题中给出的两个中的任何一个确实确实使 ghci 像您希望的那样高兴,也许您只是语法稍有错误?

Prelude> let q :: (Functor f) => f (a -> b) -> f (fa -> fb); q = fmap fmap
前奏> :tq
q :: (Functor f) => f (a -> b) -> f (fa -> fb)

Prelude> let q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b); q = fmap fmap
前奏> :tq
q :: (Functor f1, Functor f2) => f1 (a -> b) -> f1 (f2 a -> f2 b)
于 2011-04-30T11:48:31.207 回答