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

能否用Lens/Prism从Haskell的C类型中获取非Maybe的a字段?

解决方案:手动定义Getter或Lens实现确定性访问

当然可以做到——虽然自动生成的Lens无法识别所有C构造器都能提取a字段的确定性,但我们可以手动定义Getter(只读)或Lens(可读写),直接返回Int而非Maybe Int,核心是利用我们对C类型结构的完整认知,把模式匹配逻辑封装到光学组件里。

1. 只读场景:定义Getter

如果只需要读取a字段的值,可以用Getter:

import Control.Lens

data A = A { _aA :: Int } deriving (Show)
data B = B { _aB :: Int } deriving (Show)
data C = C1 A | C2 B deriving (Show)

-- 定义Getter,直接从C实例提取Int
cA :: Getter C Int
cA = to $ \case
  C1 (A x) -> x
  C2 (B x) -> x

-- 使用示例:
-- let c = C1 (A 10)
-- c ^. cA  -- 返回 10
-- let c' = C2 (B 20)
-- c' ^. cA -- 返回 20

2. 可读写场景:定义Lens

如果需要同时支持读取和修改a字段,可以定义Lens'(单目标Lens):

cALens :: Lens' C Int
cALens f = \case
  C1 (A x) -> C1 . A <$> f x
  C2 (B x) -> C2 . B <$> f x

-- 使用示例:
-- 读取值:c ^. cALens
-- 修改值:c & cALens .~ 100  -- 将c的a字段设为100
-- 增量修改:c & cALens %~ (+5) -- 将a字段加5

为什么自动生成不行?

像makeLenses这类自动工具只能基于单个类型的字段名生成光学组件,无法推断C的所有构造器都包含可提取a的子类型。但手动定义时,我们明确处理了C的所有分支,确保每个C实例都能对应唯一的Int,因此不需要用Maybe包裹结果。

这种手动定义的光学组件,本质就是把你原来的case表达式封装成了可组合的Lens/Getter,既能保留确定性访问的特性,又能享受Lens生态的组合能力。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:47:28