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

Control.Monad.Reader.withReader是否为Data.Functor.Contravariant.contramap?

关于Control.Monad.Reader与Data.Functor.Contravariant的关系

核心结论

你观察到的相似性完全成立,withReader本身就是逆变函子行为的具象实现,二者的关联核心来自Reader类型不同参数位置的方差差异:

  • 首先明确Reader r a的本质是包装了函数类型r -> a,代表接收r类型的环境、返回a类型结果的计算。
  • 我们日常使用的Reader的Functor、Applicative、Monad实例,都是针对最后一个类型参数a(结果类型)的协变实例,对应函数返回值的协变特性:fmap :: (a -> b) -> Reader r a -> Reader r b的本质就是对函数返回值做映射,和普通函数的fmap逻辑完全一致。
  • 当你固定Reader的结果类型a,将其视为「以环境类型r为参数的类型构造器」(即形如\r -> Reader r a的构造器)时,这个构造器完全符合Contravariant的定义:因为函数的入参位置本身就是逆变的,对应contramap的签名(r' -> r) -> Reader r a -> Reader r' a,和你看到的withReader签名完全匹配。
  • 标准库的Control.Monad.Reader没有直接提供Contravariant实例的原因是:Haskell的类型类实例默认作用于类型构造器的最后一个参数,Reader的最后一个参数是协变的a,如果要实现针对r的逆变实例,需要用newtype翻转参数顺序,示例如下:
{-# LANGUAGE FlexibleInstances #-}
import Data.Functor.Contravariant
import Control.Monad.Reader

newtype FlipReader a r = FlipReader (Reader r a)

instance Contravariant (FlipReader a) where
  contramap f (FlipReader m) = FlipReader $ withReader f m

这个contramap的实现逻辑和withReader完全等价:都是先将新环境r'通过传入的转换函数映射为原有环境r,再喂给原有Reader计算得到结果。

内容的提问来源于stack exchange,提问作者senjin.hajrulahovic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 17:15:06