为什么这个 Haskell 类型签名会神奇地改变?

问题描述 投票:0回答:1

我在查看免费 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

什么?为什么要检查此类型,为什么它具有给定的类型?

如果有人能够解释这里发生的事情,我们将不胜感激。我对这个模糊的标题感到抱歉,但我不太了解这里发生的事情,无法使其更具体。在回复清除后,我很高兴将其更新为更易于搜索的内容。

haskell monads functor
1个回答
2
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.