You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell:为何可在接收两个Monad值的函数上使用ap?

为什么zipWith compare ap tail能正常运行?

核心原因是你误解了ap所使用的Monad实例:这里的ap并没有用列表Monad,而是用了函数Monad(即(->) r,由接受单个参数的函数构成的Monad)。

类型推导拆解

  1. 先明确各部分的类型:

    • 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的类型会被特化为:
      ap :: (r -> x -> y) -> (r -> x) -> (r -> y)
      
      (Haskell中函数是柯里化的,r -> (x -> y)和r -> x -> y完全等价)
  2. 类型匹配:

    • 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:25:01