理解 <$> 的签名

Understanding the signature of <$>

我或多或少地了解了应用程序 <$> 运算符,但我无法理解我在以下示例中获得的签名:

ghci>  let f x y z = x + y + z  -- f::Num a => a -> a -> a -> a
ghci> f <$> Just 2 <*> Just 3 <*> Just 4 
Just 9

这个结果我明白了,但是在检查下面的类型时:

ghci> :t (<$> f)
(<$> f) :: Num a => ((a -> a -> a) -> b) -> a -> b  --This makes no sense to me

那个签名我会理解为:一个以 (a -> a- > a) -> b 函数和 a 作为参数以及 returns 和 b 的函数。根据这个推理,我应该这样称呼它:

 (<$>f) f 4

这将导致 Integer。 显然这不是真的,所以你能帮我理解如何读取 (<$> f) 的类型吗?

a function that takes a (a -> a- > a) -> b function and an a as parameters and returns a b.

这是正确的。

According to this reasoning , I should call this like :

(<$>f) f 4

which would result in an Integer.

否,因为 f 没有类型 (a -> a -> a) -> b 或与之兼容的类型。相反,它的类型为 Num a => a -> a -> a -> a。也就是说,f 接受三个数字并生成一个数字,而我们正在寻找一个将函数(a -> a -> a 类型)作为第一个参数的函数。

<$> 将类型为 g b 的东西作为第二个参数,其中 g 是任何应用函子。

您正在将 f :: Num a => a -> a -> a -> a 作为第二个参数传递。为了简单起见,让我们忽略 Num a 上下文。

因此,我们寻找 g,b 使得 g b = a -> a -> a -> a.

让我们把f的类型写成前缀形式:

f :: (->) a ((->) a ((->) a a)) = g b

因此,g = (->) ab = ((->) a ((->) a a))。后者是中缀形式的b = a -> a -> a

碰巧 (->) a 是一个应用函子,所以 <$> f 类型检查。但是请注意, <$> 用于与示例中使用的 Maybe 完全不同的仿函数。因此混乱。

TL;DR:重载的标识符可以变形为适应其上下文的许多事物,可能以某种意想不到的方式。