2017-09-09 2 views
1

Ich habe ein OuterState Objekt, das mehrere _objects enthält, die mit nestedAction geändert werden soll, die auch Zugriff auf das Objekt OuterState erfordert. Daher ist ein verschachtelter nestedAction Zustand Transformator, der für jeden InnerStateObject wie in diesem Beispiel ausgeführt wird:Ändern Sie ein verfahrbares Objektiv mit einem geschachtelten Zustand Transformator

{-# 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]} 

Die Definition von <~% in diesem Beispiel fehlt. Der Vorrang ist infixr 2 <~%. Es sollte jeden Wert von objects . traverse an execStateT nestedAction übergeben und das Ergebnis objects . traverse zuweisen.

Wie kann ich <~% implementieren? Was ist der Typ davon?


Abhängigkeiten: lts-9,3

Antwort

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

object . traverse ist zu grobkörnig, um die Aktualisierung des Felds count (implizit über nestedAction) während der Traversierung des Felds objects elegant auszudrücken. Dies ist der Grund, warum die Linsenbibliothek keinen Operator (<~%) :: MonadState s m => ATraversal' s a -> (a -> m a) -> m() hat: Sie verhält sich nicht gut, wenn ihr zweites Argument Teile des Zustands ändert, auf die auch das Traversal in seinem ersten Argument abzielt.

+0

Ihre Lösung wird nicht kompiliert. Der Ausdruck 'ruft Objekte >> = traverse (execStateT nestedAction) >> = Objekte zuweisen' resultiert in 'Konnte nicht type ... 'Fehler. Soweit ich Sie verstehe, scheint es unmöglich zu sein, '<~%' zu implementieren. Ich bin offen für alternative Lösungen. – maiermic

+0

Tut mir leid, das sollte "Objekte verwenden" statt "Objekte holen" sein. –

Verwandte Themen