Brent Yorgey出色的UPenn Haskell课程介绍:
fmap2 :: Functor f => (a -> b -> c) -> (f a -> f b -> f c)
fmap2 h fa fb = undefined
Run Code Online (Sandbox Code Playgroud)
的类型h,fa并fb细分为:
h :: a -> b -> c
fa :: f a
fb :: f b
Run Code Online (Sandbox Code Playgroud)
我不清楚为什么要h提到整个功能(a -> b -> c).
为什么不能h参考a和fa参考(b -> c)?
括号是否(a -> b -> c)有所作为?
编辑
对于任何只是在不知道所指的特定课程的情况下阅读本文的人:
fmap2不能用该签名定义.它实际上需要
liftA2 :: Applicative a => (a->b->c) -> (f a->f b->f c)
Chr*_*kle 12
是的,括号与你说的完全不同.因为(->)是右关联的,而不是数学关联,函数箭头左侧的括号表达式不能按照您的建议方式拆分:
(a -> b) -> (f a -> f b) /= a -> b -> f a -> f b
Run Code Online (Sandbox Code Playgroud)
该->运营商在这方面就像乘方运算^,这是notationally右关联,但不是数学关联:
(2 ^ 2) ^ (2 ^ 2) /= 2 ^ 2 ^ 2 ^ 2
4 ^ 4 /= 2 ^ (2 ^ (2 ^ 2))
256 /= 2 ^ (2 ^ 4)
256 /= 2 ^ 16
256 /= 65536
Run Code Online (Sandbox Code Playgroud)
(取幂的类比不是我自己的发明;函数类型是"指数类型",意思(a, b)是"产品类型",Either a b是"和类型".但请注意,这a -> b类似于b ^ a,不是a ^ b.请参阅此博客发表一个例子重的解释 ; 这个答案给出了类型代数的数学概述.)
显而易见的fmap2是,类型看起来需要一个参数,但定义看起来需要三个.对比这个版本,对我来说至少看起来更像是类型签名:
fmap2 :: Functor f => (a -> b -> c) -> (f a -> f b -> f c)
fmap2 h = \fa fb -> undefined
Run Code Online (Sandbox Code Playgroud)
现在我们有一个很好的"一个参数"的东西,fmap2 h = ...右边有一个"双参数"lambda.诀窍在于,在Haskell中,这两个表达式是等价的[*]:Haskell Report表示"函数"形式与LHS上的参数在语义上等同于lambda的简单模式绑定.
您也可以重写类型以消除箭头右侧的括号,再次因为->是右关联的:
(a -> b -> c) -> (f a -> f b -> f c)
== (a -> b -> c) -> f a -> f b -> f c
Run Code Online (Sandbox Code Playgroud)
就像
(2 ^ 2 ^ 2) ^ (2 ^ 2 ^ 2)
== (2 ^ 2 ^ 2) ^ 2 ^ 2 ^ 2
Run Code Online (Sandbox Code Playgroud)
[*]:它们在语义上是等价的,但是当用GHC编译时,它们的性能特征有时会有所不同.GHC的优化治疗f x = ...和f = \x -> ...不同.