如何使用Lenses条件设置嵌套记录与列表值并实现ensureRecAFlag函数?
使用Lenses实现ensureRecAFlag函数的方案
实现思路
按照需求优先级依次处理:
- 先检查RecB的RecA列表中是否存在
recaFlag=True的元素,若存在直接返回原对象; - 若不存在符合条件的元素,优先查找
recaName="internal_code"的RecA,找到则将其recaFlag设为True; - 若没有
internal_code的RecA,再查找recaName="id"的RecA,找到则将其recaFlag设为True; - 上述情况都不满足时,不做任何修改。
完整代码实现
import Control.Lens import Data.Text (Text) import Data.Maybe (isJust) ensureRecAFlag :: RecB -> RecB ensureRecAFlag b -- 规则1:存在recaFlag=True的RecA,直接返回原对象 | any (view flag) (b ^. recAList) = b -- 规则2:修改name为"internal_code"的RecA的flag | isJust (preview (recAList . traversed . filtered ((== "internal_code") . view name)) b) = b & recAList . traversed . filtered ((== "internal_code") . view name) . flag .~ True -- 规则3:修改name为"id"的RecA的flag | isJust (preview (recAList . traversed . filtered ((== "id") . view name)) b) = b & recAList . traversed . filtered ((== "id") . view name) . flag .~ True -- 规则4:其他情况不操作 | otherwise = b -- 原数据定义(保持不变) data RecA = RecA { recaName :: !Text , recaValue :: !Int , recaFlag :: !Bool } $(makeLensesWith abbreviatedFields ''RecA) data RecB = RecB { recbName :: !Text , recbRecAList :: ![RecA] } $(makeLensesWith abbreviatedFields ''RecB)
代码解释
- 规则1:通过
view flag提取RecA的flag字段,用any检查列表中是否存在True值; - 规则2、3:用
preview检查是否存在符合name条件的RecA,若存在则通过&运算符结合lens修改对应元素的flag。其中traversed用于遍历列表中的每个RecA,filtered筛选出符合name条件的元素,最后通过flag .~ True设置flag值; - 所有lens由
makeLensesWith abbreviatedFields自动生成,比如RecA的recaFlag对应flaglens,RecB的recbRecAList对应recAListlens。
内容的提问来源于stack exchange,提问作者Saurabh Nanda
相关产品推荐
相关产品推荐

