例如,这里是 sum 类型
data Fruit = Apple Int Color Date
| Banana Color Date
Date
是购买日期,但它位于different location
中,代表Apple
和Banana
。我可以通过 makePrisms ''Fruit
制作 Prism
是否可以创建一个像这样的镜头:
purchaseDate :: Lens Fruit Date
然后我可以轻松地
get/set/modify
在购买日期购买所有水果(苹果和香蕉)?
我认为这与如何为总和类型编写镜头不同,因为字段位置不同“日期”位于值构造函数的不同位置
如果您为字段提供通用名称,则
makeLenses
将生成适当的镜头。 也就是说,之后:
data Color = Red | Yellow deriving (Show)
newtype Date = Date Int deriving (Show)
data Fruit = Apple { _tree :: Int
, _color :: Color
, _date :: Date }
| Banana { _color :: Color
, _date :: Date }
deriving (Show)
makeLenses ''Fruit
会有
color
和 date
镜片:
λ> :t date
date :: Lens' Fruit Date
λ> Apple 1 Red (Date 20241217) ^. date
Date 20241217
λ> Banana Yellow (Date 20250101) ^. date
Date 20250101
对于不常见的字段,例如
tree
,它们将被进行遍历:
λ> :t tree
tree :: Traversal' Fruit Int
写镜头非常机械;这就是
makeLenses
存在的原因。但如果 makeLenses
不能完全实现您想要的效果,那么您当然可以自由地手写您最喜欢的变体!
purchaseDate :: Lens' Fruit Date
purchaseDate f = \case
Apple i c d -> Apple i c <$> f d
Banana c d -> Banana c <$> f d
用于提取颜色的镜头非常相似,尽管由于相当无趣的原因在语法上略有噪音。
fruitColor :: Lens' Fruit Color
fruitColor f = \case
Apple i c d -> f c <&> \c' -> Apple i c' d
Banana c d -> f c <&> \c' -> Banana c' d