5

为什么具有不同签名的函数的部分应用有效?

Control.Monad.join个例子:

GHCi> :t (=<<)
(=<<) :: Monad m => (a -> m b) -> m a -> m b
GHCi> :t id
id :: a -> a
GHCi> :t (=<<) id
(=<<) id :: Monad m => m (m b) -> m b

为什么它接受id :: a -> a代替(a -> m b)论点,因为它们显然不同?

4

3 回答 3

11

=<<的类型签名说第一个参数是从a(任何东西)到 .monad 的函数b

好吧,m b算什么,对吧?所以我们可以替换m b为 every a

(=<<) :: Monad m => (m b -> m b) -> m (m b) -> m b

ids 类型表示它是从任何事物到相同事物的函数。因此,如果我们加入m b(不要忘记 monad 约束),我们会得到:

id :: Monad m => m b -> m b

然后你可以看到类型匹配。

于 2012-08-13T16:29:25.103 回答
3

一些有用的概念在这里使用:

  1. 任何带有变量的类型都可以通过将 的每个实例替换为任何其他类型a来转换为不同的类型。因此,如果您有 type ,您可以通过分别替换with或with来获取 type或 type 。ata -> b -> ca -> d -> ca -> b -> IntbdcInt
  2. 任何可以通过替换相互转换的两种类型都是等价的。例如,a -> bc -> d是等价的 ( a~ c, b~ d)。
  3. 如果一个类型t可以转换为一个类型t',但t'不能转换回一个类型t,那么我们就说它t'是 的一个t。例如,a -> aa -> b.

现在,有了这些非常有用的概念,您的问题的答案就很简单了:即使函数的“本机”类型不完全匹配,它们也是兼容的,因为它们可以被重写或专门化以获得精确匹配。Matt Fenwick 的回答显示了针对这种情况的专业化。

于 2012-08-13T20:55:46.813 回答
2

它试图与 统一am b并简单地决定它a必须是m b,所以(=<<)(在假设下a ~ m b)的类型是Monad m => (mb -> m b) -> m (m b) -> m b,一旦你将它应用到id,你就剩下 了Monad m => m (m b) -> m b

于 2012-08-13T16:27:21.817 回答