我的应用<$>
运算符或多或少已经弄明白了,但我无法理解我通过以下示例获得的签名:
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
作为参数并返回b
。根据这个推理,我应该这样称呼:
(<$>f) f 4
会产生Integer
。
显然这不是真的,所以请你帮我理解如何阅读(<$> f)
的类型?
答案 0 :(得分:3)
以
(a -> a- > a) -> b
函数和a
作为参数并返回b
的函数。
这是正确的。
根据这个推理,我应该这样称呼:
(<$>f) f 4
会产生
Integer
。
不,因为f
没有(a -> a -> a) -> b
类型或与之兼容的类型。相反,它的类型为Num a => a -> a -> a -> a
。也就是说,f
取三个数字并产生一个数字,而我们正在寻找一个函数(函数类型为a -> a -> a
)作为其第一个参数。
答案 1 :(得分:1)
<$>
将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 = (->) a
和b = ((->) a ((->) a a))
。后者以中缀形式b = a -> a -> a
。
恰好(->) a
是一个应用函子,所以<$> f
类型检查。但请注意,<$>
用于与您在示例中使用的Maybe
完全不同的仿函数。因此混乱。
TL; DR:重载的标识符可以变换为适应其上下文的许多事物,可能以某种意想不到的方式。