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

如何使用choosing?构造Lens' Foo Int类型透镜的问题探究

Haskell中构造Foo类型的Int透镜问题

数据类型定义

data SomeNestedData = SomeNestedData { sndValue :: Int }
data OtherNestedData = OtherNestedData { ondValue :: Int }
data Foo = Bar SomeNestedData | Baz OtherNestedData

需求

构造一个类型为Lens' Foo Int的透镜,使其能对任意foo :: Foo值进行Int类型值的获取与设置。

尝试实现及问题

尝试用choosing结合标准透镜、棱镜编写代码:

lensFooInt :: Lens' (Either Foo Foo) Int
lensFooInt = (_Bar . _sndValue ) `choosing` (_Baz . ondValue)

但lensFooInt的类型是Lens' (Either Foo Foo) Int,不符合预期的Lens' Foo Int,由此提出两个问题:

  1. 如何有意义地使用lensFooInt?Either类型似乎无法按预期运作。
  2. 是否存在实现lensFooInt' :: Lens' Foo Int的方法?

解答

关于lensFooInt的使用

lensFooInt只能作用于Either Foo Foo类型的值,且要求左边的Foo必须是Bar构造的实例,右边的Foo必须是Baz构造的实例——只有这种情况下,棱镜_Bar和_Baz才能匹配成功,透镜才能正常获取或修改嵌套的Int值。如果左边是Baz或者右边是Bar,使用这个透镜会直接失败。它的适用场景非常狭窄,完全达不到处理任意Foo值的需求。

实现Lens' Foo Int的方法

存在,就是你补充给出的代码:

lensFooInt' = re _Right . ((_Bar . _sndValue ) `choosing` (_Baz . ondValue))

核心在于re _Right:_Right是一个针对Either a b的棱镜(Prism' (Either a b) b),re可以将棱镜反转成一个同构(Iso),把单个Foo值包装成Either Foo Foo的右分支。之后结合choosing组合的透镜,就能对任意Foo值生效:

  • 当处理Bar实例时,_Bar匹配成功,操作对应的sndValue;
  • 当处理Baz实例时,_Baz匹配成功,操作对应的ondValue。
    完全满足对任意Foo值进行Int获取与设置的需求。

内容的提问来源于stack exchange,提问作者ruben.moor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:57:21