I want to map a function of type Float -> Float
over a part of a data structure which looks like this.
VDstruct { _onBuild = Just True
, _imageName = Just "arc.png"
, _category = Just "All"
, _mmo = Just 210
, _structTypes = Just
( Mage
{ _ict = Nothing
, _create = Just 1.24
, _sh = Nothing
}
}
I want to apply that function to _ict
, _create
and to _sh
.
I know how to do that for each one of those.
I'm using Lenses to help me out with that.
The result has _create = Just 5.4
which is exactly what I expect from plusXPercent
function.
This is what I'm using right now.
setSer x = x & (structTypes . _Just . create) %~ fmap plusXPercent
What I want to do is instead of naming every _ict
, _sh
, etc. I want a way to 'map' that function over the entirety of Mage
structure.
How should I go about doing that?
Edit: _ict
, _create
and _sh
have type Maybe Float
and Mage
is defined like this
data Mage = Mage { _ict :: Maybe Float
, _create :: Maybe Float
, _sh :: Maybe Float
} deriving Show
答案 0 :(得分:4)
如果您想使用mono-traversable
包,则可以为MonoFunctor
定义一个Mage
实例。
type instance Element Mage = Maybe Float
instance MonoFunctor Mage where
omap f (Mage x y z) = Mage (f x) (f y) (f z)
然后,您可以使用omap
将fmap (+1)
应用于(例如)每个字段
的Mage
。
omap (fmap (+1)) (Mage { _ict = Nothing
, _create = Just 1.24
, _sh = Nothing
})
== Mage { _ict = Nothing, _create = Just 2.24, _sh = Nothing }
然后,我想,你会写(对不起,只是猜测,镜头不是我的强项):
--setSer x = x & (structTypes . _Just . create) %~ fmap plusXPercent
setSer x = x & (structTypes . _Just) %~ (omap (fmap plusXPercent))
但是,MonoFunctor
可能会过大。您可以使用Applicative
函数实例来完成相同的事情。
foo :: (Maybe Float -> Maybe Float) -> Mage -> Mage
foo f = Mage <$> f . _ict <*> f . _create <*> f . _sh
答案 1 :(得分:3)
您始终可以手动编写遍历,这就是需要这样做的地方。镜头有一个适用于此的课程,Each
。
instance (a ~ Float, b ~ Float) => Each Mage Mage a b where
each f (Mage i c s) = Mage <$> traverse f i <*> traverse f c <*> traverse f s
您也可以在不使用类的情况下编写遍历,但也可以在适当时重用该名称。