首页 > 解决方案 > 如何在嵌套数据结构的一部分上映射函数?

问题描述

我想在Float -> Float看起来像这样的数据结构的一部分上映射一个类型的函数。

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                                                                                                                                                                                     
                   }    
         }

我想将该功能应用于_ict和。_create_sh

我知道如何为其中的每一个做到这一点。我正在使用镜头来帮助我解决这个问题。结果_create = Just 5.4正是我对plusXPercent函数的期望。这就是我现在正在使用的。

setSer x = x & (structTypes . _Just . create) %~ fmap plusXPercent

我想要做的不是命名每个_ict,_sh等。我想要一种方法来“映射”整个Mage结构上的功能。

我该怎么做呢?

编辑:_ict_create_sh有类型Maybe Float

并且Mage是这样定义的

data Mage = Mage { _ict :: Maybe Float
                 , _create :: Maybe Float
                 , _sh :: Maybe Float
                 } deriving Show

标签: haskelldata-structures

解决方案


如果要使用mono-traversable包,可以MonoFunctorMage.

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

推荐阅读