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

如何使用Traversal移除列表中特定值构造器(保留Banana)

解决方案

步骤1:定义针对Banana的Traversal

你可以选择手动定义Traversal,也可以用TemplateHaskell自动生成Prism(Prism属于Traversal的子类,完全满足需求)。

手动定义Traversal
import Control.Lens

data Fruit = Apple Int
           | Banana Color Int
           deriving (Show)

data Color = Red
           | Green
           deriving (Show)

-- 仅聚焦Banana构造器的Traversal
_Banana :: Traversal' Fruit Fruit
_Banana f banana@(Banana _ _) = f banana
_Banana f apple@(Apple _) = pure apple
自动生成Prism(更简洁)

启用TemplateHaskell后,工具会自动为Fruit的每个构造器生成对应的Prism:

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens

data Fruit = Apple Int
           | Banana Color Int
           deriving (Show)

data Color = Red
           | Green
           deriving (Show)

-- 自动生成_Apple和_Banana两个Prism
makePrisms ''Fruit

步骤2:移除Apple,仅保留Banana

利用^..(toListOf的运算符形式)提取所有匹配_Banana的元素,即可得到仅含Banana的列表:

let basket = [Apple 3,Banana Red 30,Apple 6]
onlyBananas :: [Fruit]
onlyBananas = basket ^.. traverse . _Banana
-- 结果:[Banana Red 30]

额外:用该Traversal执行修改/设置操作

这个Traversal完全支持你提到的修改、设置操作:

修改操作(over)

给所有Banana的数值加10:

-- 方式1:直接修改整个Banana构造器
updatedBananas :: [Fruit]
updatedBananas = over (traverse . _Banana) 
                      (\(Banana c n) -> Banana c (n + 10)) 
                      basket
-- 结果:[Apple 3, Banana Red 40, Apple 6]

-- 方式2:聚焦到Banana的第二个字段(更简洁)
updatedBananas' :: [Fruit]
updatedBananas' = over (traverse . _Banana . _2) (+10) basket
设置操作(set)

把所有Banana的颜色设为Green:

greenBananas :: [Fruit]
greenBananas = set (traverse . _Banana . _1) Green basket
-- 结果:[Apple 3, Banana Green 30, Apple 6]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:13:10