Я пытаюсь определить семейство государственных машин с несколько различными типами состояний. В частности, более «сложные» конечные автоматы имеют состояния, которые формируются путем объединения состояний более простых конечных автоматов.
(Это похоже на объектно-ориентированную настройку, где объект имеет несколько атрибутов, которые также являются объектами.)
Вот упрощенный пример того, чего я хочу достичь.
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
Для контекста это то, чего я хочу достичь с помощью этого механизма:
Я хочу создать такие вещи, как «потоковые трансформеры», которые в основном являются функциями с состоянием: они потребляют токен, изменяют свое внутреннее состояние и что-то выводят. В частности, меня интересует класс Stream Transformers, где выводом является логическое значение; мы будем называть эти «мониторы».
Сейчас я пытаюсь разработать комбинаторы для этих объектов. Некоторые из них:
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специализируется на монады).