Haskell中(+) <$> (+3) <*> (*100)函子表达式含义解析
解读Haskell表达式
:t (+) <$> (+3) <*> (*100) 首先你对优先级和结合性的判断完全正确:<$>和<*>优先级相同且左结合,所以这个表达式确实等价于((+) <$> (+3)) <*> (*100)。下面一步步拆解它的作用:
1. 先看 (+) <$> (+3)
<$>是fmap的中缀形式,对于函数类型(这里属于Reader Monad范畴),fmap f g的行为是把f作用在g的输出上:
(+)的类型是Num a => a -> a -> a,是一个接受第一个数、返回“等待第二个数的加法函数”的二元函数;(+3)的类型是Num a => a -> a,是接受一个数x、返回x+3的函数。
用fmap把(+)映射到(+3)上,得到的结果是\x -> (+) (x+3)——也就是一个接受x、返回“等待第二个数y,计算(x+3)+y”的函数,类型为Num a => a -> a -> a。
2. 再看和(*100)的<*>运算
<*>是Applicative的中缀操作符,对于函数类型,它的定义是f <*> g = \x -> f x (g x)——简单说就是让左右两个函数共享同一个输入x,然后把左边函数的输出(一个函数)应用到右边函数的输出上。
把第一步得到的\x -> (x+3)+和(*100)代入<*>,展开后就是:
\x -> (x+3) + (x*100)
简化后为\x -> 101*x + 3,类型是Num a => a -> a。
关于《Learn You a Haskell for Great Good》里的描述
书中说“将+用于(+10)和(+5)的未来返回值”,这是从Applicative/Reader Monad的“共享环境”角度解释的:
(+)是我们要执行的二元操作,<$>先把它和左边的(+10)绑定,相当于“先记住要把(+10)的结果作为+的第一个参数”;<*>再把右边的(+5)绑定过来,相当于“再记住要把(+5)的结果作为+的第二个参数”;- 最终得到的是一个“等待输入
x”的函数,当x传入时,同时计算x+10和x+5,再把它们相加。
这个描述和左结合的计算逻辑完全一致——左结合只是运算的顺序,本质是Applicative让两个函数共享同一个输入,把二元操作的两个参数分别绑定到两个函数的输出上,最后合并结果。
内容的提问来源于stack exchange,提问作者helloword
相关产品推荐
相关产品推荐

