2017-09-09 19 views
1

J'ai un objet OuterState qui contient plusieurs _objects qui doit être modifié en utilisant nestedAction qui nécessite également l'accès à l'objet OuterState. Par conséquent, nestedAction est un transformateur d'état imbriqué qui est exécuté pour chaque InnerStateObject comme dans cet exemple:Modification d'une lentille traversable à l'aide d'un transformateur d'état imbriqué

{-# LANGUAGE TemplateHaskell #-} 

module Main where 

import Control.Lens ((+=), makeLenses) 
import Control.Monad.IO.Class (liftIO) 
import Control.Monad.State.Lazy 
     (StateT, evalStateT, execStateT, get) 
import Control.Monad.Trans.Class (lift) 

data OuterState = OuterState 
    { _objects :: [InnerStateObject] 
    , _count :: Int 
    } deriving (Show) 

data InnerStateObject = InnerStateObject 
    { _value :: Int 
    } deriving (Show) 

makeLenses ''OuterState 

makeLenses ''InnerStateObject 

startNestedAction :: StateT OuterState IO() 
startNestedAction = do 
    get >>= liftIO . putStrLn . ("before: " ++) . show 
    objects . traverse <~% execStateT nestedAction 
    get >>= liftIO . putStrLn . ("after: " ++) . show 

nestedAction :: StateT InnerStateObject (StateT OuterState IO)() 
nestedAction = do 
    value += 10 
    lift $ count += 100 

main :: IO() 
main = 
    evalStateT 
    startNestedAction 
    OuterState {_count = 0, _objects = map InnerStateObject [0 .. 2]} 

La définition de <~% manque dans cet exemple. La priorité est infixr 2 <~%. Il doit transmettre chaque valeur de objects . traverse à execStateT nestedAction et affecter le résultat à objects . traverse.

Comment puis-je implémenter <~%? Quel est le type?


dépendances: lts-9.3

Répondre

1
use objects >>= traverse (execStateT nestedAction) >>= assign objects 

object . traverse est trop grossier pour exprimer élégamment la mise à jour du champ count (implicite via nestedAction) pendant la traversée du champ objects. C'est essentiellement pourquoi la bibliothèque de lentilles n'a pas d'opérateur (<~%) :: MonadState s m => ATraversal' s a -> (a -> m a) -> m(): elle ne se comporte pas bien si son deuxième argument modifie des parties de l'état qui sont également ciblées par la traversée dans son premier argument.

+0

Votre solution ne compile pas. L'expression 'gets objects >> = traverse (execStateT nestedAction) >> = assigner des objets' a pour résultat des erreurs 'Could not match type ...'. Pour autant que je te comprends il semble qu'il ne soit pas possible d'implémenter '<~%'. J'ai l'esprit ouvert sur les solutions alternatives. – maiermic

+0

Désolé, cela aurait dû être 'use objects' au lieu de' gets objects'. –