Haskell:为何可在接收两个Monad值的函数上使用ap?
为什么
zipWith compare ap tail能正常运行? 核心原因是你误解了ap所使用的Monad实例:这里的ap并没有用列表Monad,而是用了函数Monad(即(->) r,由接受单个参数的函数构成的Monad)。
类型推导拆解
先明确各部分的类型:
zipWith compare的类型:将compare :: a -> a -> Ordering代入zipWith :: (x -> y -> z) -> [x] -> [y] -> [z],得到zipWith compare :: [a] -> [a] -> [Ordering](zipWith会把compare应用到两个列表的每一对元素,返回结果列表)。tail的类型:[a] -> [a],接受一个列表返回它的尾列表。ap的特化类型:当Monad实例为函数Monad(->) r时,m t等价于r -> t,因此ap的类型会被特化为:
(Haskell中函数是柯里化的,ap :: (r -> x -> y) -> (r -> x) -> (r -> y)r -> (x -> y)和r -> x -> y完全等价)
类型匹配:
zipWith compare :: [a] -> [a] -> [Ordering]正好匹配ap第一个参数的r -> x -> y形式:r = [a],x = [a],y = [Ordering]。tail :: [a] -> [a]正好匹配ap第二个参数的r -> x形式。
实际行为
函数Monad的ap实现逻辑是:用同一个输入分别调用两个函数,再把第二个函数的结果传给第一个函数的第二个参数。具体代码是:
ap f g = \x -> f x (g x)
因此zipWith compare ap tail完全等价于:
\xs -> zipWith compare xs (tail xs)
这个函数接受一个列表xs,返回xs与tail xs逐元素比较的Ordering列表(比如输入[3,1,4]会得到[GT, LT])。
内容的提问来源于stack exchange,提问作者Ed Lim
相关产品推荐
相关产品推荐

