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

Haskell Lens中兼具Getter与Setter的函数类型签名问询

问题1:同时支持& f %~和^. f的函数类型签名

能同时用^.(取值)和%~(修改)调用的函数,本质是Lens库中的Lens类型。它的核心类型签名为:

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t

如果只需要处理同类型的状态(比如修改同一个类型的字段,无需转换类型),可以用更简洁的别名Lens':

type Lens' s a = Lens s s a a

为什么它能适配两种调用方式?

  • 当用^.取值时,Haskell会自动选用Const这个Functor,此时Lens的类型会适配成Getting a s a(Getter的标准类型),完美支持取值操作。
  • 当用%~修改时,Haskell会选用Identity Functor,此时Lens的类型适配成Setter s t a b,满足修改字段的需求。

问题2:_func的类型与泛化后的setToPercent

_func的完整类型

从你的代码行为来看,_func既能通过^.获取Maybe Float,又能通过%~修改对应的字段,而且MyDataType和Weapon结构一致。它的完整类型应该是:

_func :: Lens' MyDataType (Maybe Float)

如果需要兼容Weapon类型(比如允许从MyDataType取值,修改Weapon),也可以写成更泛化的形式:

_func :: Lens MyDataType Weapon (Maybe Float) (Maybe Float)

这里要澄清一点:你提到_func是“记录语法生成的MyDataType -> Maybe Float函数”——这其实是字段访问器的类型,但字段访问器本身不能直接用%~。你能这么用,肯定是借助Template Haskell(比如makeLenses)生成了对应字段的Lens,而且生成的Lens名字和字段名(_func)一致(默认makeLenses会去掉下划线前缀,你可能调整了lensRules来保留下划线)。

泛化后的setToPercent类型

当你把_func换成通用的fnToApply参数后,这个参数需要同时支持取值和修改,也就是Lens' s (Maybe Float)类型。泛化后的函数完整签名是:

setToPercent :: Lens' s (Maybe Float) -> Float -> s -> s -> s

如果想要支持不同的源类型和目标类型(比如从类型s取值,修改类型t),可以写成更灵活的版本:

setToPercent :: Lens s t (Maybe Float) (Maybe Float) -> Float -> s -> t -> t

但从你的代码逻辑来看,basedOn和toSetOn是同结构的类型,第一个简化版的Lens'已经完全够用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:42:57