为什么具有不同签名的函数的部分应用有效?
举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)论点,因为它们显然不同?
为什么具有不同签名的函数的部分应用有效?
举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)论点,因为它们显然不同?
=<<的类型签名说第一个参数是从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
然后你可以看到类型匹配。
一些有用的概念在这里使用:
a来转换为不同的类型。因此,如果您有 type ,您可以通过分别替换with或with来获取 type或 type 。ata -> b -> ca -> d -> ca -> b -> IntbdcInta -> b和c -> d是等价的 ( a~ c, b~ d)。t可以转换为一个类型t',但t'不能转换回一个类型t,那么我们就说它t'是 的一个特化t。例如,a -> a是a -> b.现在,有了这些非常有用的概念,您的问题的答案就很简单了:即使函数的“本机”类型不完全匹配,它们也是兼容的,因为它们可以被重写或专门化以获得精确匹配。Matt Fenwick 的回答显示了针对这种情况的专业化。
它试图与 统一a,m 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。