Sto cercando di definire una famiglia di macchine a stati con tipi di stati alquanto diversi. In particolare, le macchine a stati più "complesse" hanno stati che si formano combinando gli stati di macchine a stati più semplici.
(È simile a un'impostazione orientata agli oggetti in cui un oggetto ha diversi attributi che sono anche oggetti.)
Ecco un esempio semplificato di ciò che voglio ottenere.
data InnerState = MkInnerState { _innerVal :: Int }
data OuterState = MkOuterState { _outerTrigger :: Bool, _inner :: InnerState }
innerStateFoo :: Monad m => StateT InnerState m Int
innerStateFoo = do
i <- _innerVal <$> get
put $ MkInnerState (i + 1)
return i
outerStateFoo :: Monad m => StateT OuterState m Int
outerStateFoo = do
b <- _outerTrigger <$> get
if b
then
undefined
-- Here I want to "invoke" innerStateFoo
-- which should work/mutate things
-- "as expected" without
-- having to know about the outerState it
-- is wrapped in
else
return 666
Più in generale, desidero un framework generalizzato in cui questi nidificazione siano più complessi. Ecco qualcosa che vorrei sapere come fare.
class LegalState s
data StateLess
data StateWithTrigger where
StateWithTrigger :: LegalState s => Bool -- if this trigger is `True`, I want to use
-> s -- this state machine
-> StateWithTrigger
data CombinedState where
CombinedState :: LegalState s => [s] -- Here is a list of state machines.
-> CombinedState -- The combinedstate state machine runs each of them
instance LegalState StateLess
instance LegalState StateWithTrigger
instance LegalState CombinedState
liftToTrigger :: Monad m, LegalState s => StateT s m o -> StateT StateWithTrigger m o
liftToCombine :: Monad m, LegalState s => [StateT s m o] -> StateT CombinedState m o
Per il contesto, questo è ciò che voglio ottenere con questo macchinario:
Voglio progettare queste cose chiamate "Transformers Stream", che sono sostanzialmente funzioni stateful: consumano un token, mutano il loro stato interno e producono qualcosa. In particolare, sono interessato a una classe di trasformatori di flusso in cui l'output è un valore booleano; chiameremo questi "monitor".
Ora sto cercando di progettare combinatori per questi oggetti. Alcuni di loro sono:
- Un
pre
combinatore. Supponiamo chemon
sia un monitor. Quindi,pre mon
è un monitor che produce sempreFalse
dopo che il primo token è stato consumato e quindi imita il comportamento dimon
come se il token precedente fosse stato inserito ora. Vorrei modellare lo stato dipre mon
withStateWithTrigger
nell'esempio sopra dato che il nuovo stato è un valore booleano insieme allo stato originale. - Un
and
combinatore. Supponiamo chem1
em2
siano monitor. Quindi,m1 `and` m2
è un monitor che invia il token a m1, quindi a m2 e quindi produceTrue
se entrambe le risposte fossero vere. Vorrei modellare lo stato dim1 `and` m2
withCombinedState
nell'esempio sopra dato che lo stato di entrambi i monitor deve essere mantenuto.
StateT InnerState m Int
valore in primo luogo in outerStateFoo
?
_innerVal <$> get
è sologets _innerVal
(comegets f == liftM f get
, edliftM
è solofmap
specializzato in monadi).