如何组合多个镜头(不是合成)?

21

在没有使用lenses的Haskell中,我可以做如下操作:

data Item = Item { quantity :: Double, price ::Double }

cost :: Item -> Double
cost = (*) <$> quantity <*> price

如果我使用镜头,如何实现同样的效果?我能做到的最好的是

cost = to $ (*) <$> (^. quantity) <*> (^. price)

有更好的方法吗?(当然我想要一个getter或等效物)


4
应该写成cost = (*) <$> (^. quantity) <*> (^. price)吗? - Aadit M Shah
4
你可以创建两个新的操作符:f <$>. l = f <$> (^. l)f <*>. l = f <*> (^. l)。然后你的表达式变成了cost = (*) <$>. quantity <*>. price - Aadit M Shah
10
你为什么要将答案发布为评论? - Bakuriu
3
我猜想没有人认为他们的答案比mb14的原创更好。 - duplode
2
我刚刚偶然发现了@danidiaz的这个答案,其中建议使用Control.Lens.Reified:只读光学包装器具有您期望的函数实例,因此您可以执行runGetter ((*) <$> Getter quantity <*> Getter price) - duplode
显示剩余9条评论
1个回答

2

我突然想到,你不需要任何特殊的语法来组合镜头。如果你正在使用模板Haskell创建镜头(你应该这样做),那么你已经有了每个字段的原始getter,前面带有下划线。

因此,你可以使用原始getter来创建你的幻影cost getter,如下所示:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

data Item = Item { _quantity :: Double
                 , _price    :: Double
                 }

$(makeLenses ''Item)

cost :: Getter Item Double
cost = to $ (*) <$> _quantity <*> _price

item :: Item
item = Item { _quantity = 2, _price = 5.0 }

main :: IO ()
main = print $ view cost item

然而,如果您无法访问原始的获取器,则可以将cost定义为:

cost :: Getter Item Double
cost = to $ (*) <$> view quantity <*> view price

您的手指不需要离开主键盘区域太远就能打出view


我正在尝试组合镜头,因为它们可能不对应记录访问器,因此使用原始getter是不可行的。然而,我同意view lens(^. lens)更好。 - mb14

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接