Я намагаюся визначити сімейство державних машин з дещо різними видами станів. Зокрема, більш "складні" державні машини мають стани, які утворюються шляхом об'єднання станів більш простих державних машин.
(Це схоже на об'єктно-орієнтовану установку, коли об’єкт має кілька атрибутів, які також є об'єктами.)
Ось спрощений приклад того, що я хочу досягти.
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
Загалом, я хочу узагальнити рамки, де ці гнізда більш складні. Ось я хотів би знати, як це зробити.
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
У контексті цього я хочу досягти завдяки цій техніці:
Я хочу створити ці речі під назвою "Трансформатори потоку", які в основному є функціональними станами: Вони споживають маркер, мутують свій внутрішній стан і щось виводять. Зокрема, мене цікавить клас потокових трансформаторів, де на виході є булеве значення; ми будемо називати цих "моніторів".
Зараз я намагаюся створити комбінатори для цих об’єктів. Деякі з них:
preКомбінатор. Припустимо,monце монітор. Потім,pre monце монітор, який завжди виробляєтьсяFalseпісля споживання першого маркера, і потім імітує поведінку так,monяк ніби вставляється попередній маркер. Я хотів би продемонструвати станpre monзStateWithTriggerу наведеному вище прикладі, оскільки новий стан є булевим разом із початковим станом.andКомбінатор. Припустимо, що цеm1іm2монітори. Потім,m1 `and` m2це монітор, який подає маркер до m1, а потім до m2, а потім виробляє,Trueякщо обидва відповіді були правдивими. Я хотів би, щоб змоделювати станm1 `and` m2зCombinedStateв наведеному вище прикладі , так як стан обох моніторів повинні бути збережені.
StateT InnerState m Intцінність в першу чергу outerStateFoo?
_innerVal <$> getє справедливимgets _innerVal(якgets f == liftM f get, і спеціалізуєтьсяliftMтількиfmapна монадах).