绑定到参数的函数类型

Kev*_*ith 3 haskell

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,fafb细分为:

h  :: a -> b -> c
fa :: f a
fb :: f b
Run Code Online (Sandbox Code Playgroud)

我不清楚为什么要h提到整个功能(a -> b -> c).

为什么不能h参考afa参考(b -> c)

括号是否(a -> b -> c)有所作为?

编辑

考虑leftaroundabout评论:

对于任何只是在不知道所指的特定课程的情况下阅读本文的人: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 -> ...不同.