Haskell - fmap函数无法工作

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 时,我得到了与上面相同的类型。

我做错了什么?为什么 fmap fmap 会产生类型错误,尽管 GHCi找到了它的类型?

2个回答

7

看起来你遇到了单态限制

在GHCi中使用-XNoMonomorphismRestriction参数尝试你的示例即可得到期望的结果。

你也可以通过编写let f x = fmap fmap $ x来规避这个问题。单态限制仅适用于顶层定义,这些定义“看起来像”值,例如f = something,因此引入显式参数使其不再适用。如果这不是在顶层(例如在where子句中),它也不会适用。有关更多详细信息,请参见链接。


1
似乎是单态限制,因为你的解决方案起作用了。谢谢。但是当我指定类型时为什么不起作用? - Mafi

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)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接