我在查看免费 monad 时遇到了这个问题,但已将其简化为一个更小的示例。
在 Haskell 中,我们有以下类型:
fmap :: Functor f => (a -> b) -> f a -> f b
假设我们还有以下函数:
foo :: Num a => p -> a
foo = \_ -> 1
然后
fmap foo :: (Functor f, Num b) => f a -> f b
-- and
fmap (fmap foo)
:: (Functor f1, Functor f2, Num b) => f1 (f2 a) -> f1 (f2 b)
那么人们会期望我们只能将
fmap (fmap foo)
应用于 (Functor f1, Functor f2) => f1 (f2 a)
类型的东西,但是
fmap (fmap foo) foo :: (Functor f, Num b, Num (f a)) => p -> f b
什么?为什么要检查此类型,为什么它具有给定的类型?
如果有人能够解释这里发生的事情,我们将不胜感激。我对这个模糊的标题感到抱歉,但我不太了解这里发生的事情,无法使其更具体。在回复清除后,我很高兴将其更新为更易于搜索的内容。
foo
是一个函数,因此在其上使用 fmap
(作为第二个参数)会选择 函数的
Functor
实例,其中 fmap = (.)
。所以你问为什么 fmap foo . foo
具有给定的类型,这是一个简单的统一问题:
foo :: Num x => p -> x
fmap foo :: (Functor f, Num b) => f a -> f b
因此我们有
x = f a
并且生成的类型签名是 (Num (f a), Functor f, Num b) => p -> f b
。