Как отобразить функцию на часть вложенной структуры данных? - PullRequest
0 голосов
/ 07 января 2019

Я хочу отобразить функцию типа 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

Ответы [ 2 ]

0 голосов
/ 07 января 2019

Вы всегда можете написать обходы вручную, и это то, к чему это призывает. У объектива есть класс, который применим здесь: 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

Вы также можете написать этот обход без класса, но вы также можете повторно использовать имя, когда это уместно.

0 голосов
/ 07 января 2019

Если вы хотите использовать пакет 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...