gpt4 book ai didi

haskell - 使用 ekmett 的 Lens 更新一个字段的多个子字段

转载 作者:行者123 更新时间:2023-12-04 14:46:33 24 4
gpt4 key购买 nike

来玩个游戏。我们将使用两堆,均由黑/白边芯片组成。

data Pile = Pile { _blacks, _whites :: Int }
makeLenses ''Pile

data Game = Game { _pileA, _pileB :: Pile }
makeLenses ''Game

一个非常聪明的举动是在 A 堆中翻出黑色筹码,在 B 堆中翻出白色筹码。但是怎么做呢?
cleverMove :: Game -> Game
cleverMove game = game & pileA . blacks -~ 1
& pileA . whites +~ 1
& pileB . blacks +~ 1
& pileB . whites -~ 1

不是很优雅。如果不引用每个桩两次,我怎么能做到这一点?

我想出的唯一一件事(我不喜欢它):
cleverMove game = game & pileA %~ (blacks -~ 1)
. (whites +~ 1)
& pileB %~ (blacks +~ 1)
. (whites -~ 1)

(如果很明显,请提前抱歉 - 我对镜头有点陌生,我在组合器和运算符(operator)的海洋中迷失了 lens 报价。可能每个人都需要的东西都藏在那里。当然不是说这很糟糕!但我希望还包括一个完整的手册。)

最佳答案

一个 TraversalLens 的概括它“关注”多个值。把它想象成 traverse它允许您单步执行 Traversable t修改 Applicative 中的值( traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b) 看起来很像 Lens 的类型,你会注意到——想想 t b ~ whole )。

对于 Traversal我们可以选择我们想要更改的值。例如,让我概括一下您的 Pile有点建了Traversal .

data Pile = Pile { _blacks :: Int, _whites :: Int, _name :: String } deriving (Show)
$(makeLenses ''Pile)

counts :: Traversal' Pile Int
counts f (Pile blacks whites name) =
Pile <$> f blacks <*> f whites <*> pure name

如您所见,我访问了 blackswhitesf但离开 name pure .这几乎与您编写 Traversable 的方式相同。实例,除非您总是访问 Traversable 中包含的所有(同质)元素。结构体。
Main*> Pile 0 0 "test" & counts +~ 1
Pile {_blacks = 1, _whites = 1, _name = "test"}

但是,这还不足以满足您的需求,因为您需要以不同的方式更新您的字段。为此,您需要指定您的逻辑并确保它支持一组完全不同的规则。
blackToWhite :: Pile -> Pile
blackToWhite = (blacks -~ 1) . (whites +~ 1)

关于haskell - 使用 ekmett 的 Lens 更新一个字段的多个子字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16888491/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com