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

如何理解Haskell中lambda表达式\g x -> fmap ($) g x里的functor

核心问题解答

1. 第一个表达式的Functor位置

你疑惑的Functor是函数类型(->) t,Haskell中所有「接受固定类型输入的函数」都实现了Functor实例,这个实例的fmap就是普通的函数组合(.),定义为:

instance Functor ((->) r) where
  fmap f g = f . g

我们一步步推导第一个表达式\g x -> fmap ($) g x的类型:

  • 首先($)的类型是(a -> b) -> a -> b,可以简化看成(a->b) -> (a->b)(本质就是给函数套了个中缀调用的壳,功能和id对函数的作用等价)
  • 因为函数调用是左结合的,原式等价于((fmap ($)) g) x
  • 把($)传入fmap,当Functor是(->) t时,fmap的签名就特化为:(a'->b') -> (t->a') -> (t->b')
  • 代入($)作为第一个参数,得到fmap ($)的类型是(t -> (a->b)) -> (t -> (a->b))
  • 再把g传入,得到fmap ($) g的类型是t -> (a->b),等价于\x -> ($) (g x)
  • 最后传入x参数,就得到($) (g x) = \a -> g x a,整个表达式的功能就是把g的两个参数依次传入,等价于id,所以类型就是你看到的(t -> a -> b) -> t -> a -> b

2. 三个表达式类型差异的原因

三个表达式的本质区别是括号和$运算符的优先级导致fmap接收的参数完全不同:

表达式2:\g x -> fmap ($) (g x)

这里括号明确把g x作为fmap的第二个参数,所以:

  • fmap的第一个参数是($) :: (a->b) -> (a->b)
  • 第二个参数g x的类型必须是Functor f => f (a->b),也就是g的类型是t -> f (a->b)
  • 所以fmap返回的就是f (a->b),最终整个表达式的类型就是你看到的Functor f => (t -> f (a -> b)) -> t -> f (a -> b)
    这里的Functor是g x所属的任意Functor实例f,不再是函数类型。

表达式3:\g x -> fmap $ g x

$是Haskell中优先级最低的运算符,作用是把右侧的整个表达式作为参数传给左侧,所以原式等价于\g x -> fmap (g x):

  • 这里fmap的第一个参数变成了g x,类型是a -> b
  • fmap的第二个参数被留空了,等待后续传入Functor f => f a类型的值
  • 所以整个表达式的类型就是Functor f => (t -> a -> b) -> t -> f a -> f b,和你看到的一致。

内容的提问来源于stack exchange,提问作者tkrd

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 11:54:04