我正在尝试定义状态机家族,它们的状态有些不同。特别地,更“复杂”的状态机具有通过组合更简单的状态机的状态而形成的状态。
(这类似于面向对象的设置,其中对象具有多个属性,这些属性也是对象。)
这是我要实现的简化示例。
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
with 的状态进行建模StateWithTrigger
,因为新状态和原始状态都是布尔值。 - 一个
and
组合子。假设m1
和m2
是监视器。然后m1 `and` m2
是一个监视器,该监视器将令牌馈送给m1,然后馈送到m2,然后生成True
两个答案是否均为真的信息。我想在上面的示例中对m1 `and` m2
with 的状态进行建模CombinedState
,因为必须保持两个监视器的状态。
您
—
chepner
StateT InnerState m Int
首先从哪里获得价值outerStateFoo
?
@卡尔我看过一些镜头,但不太了解。也许您可以在答案中解释如何使用缩放?
—
Agnishom Chattopadhyay
观察:此条目不包含单个问题。
—
Simon Shine
_innerVal <$> get
只是gets _innerVal
(如gets f == liftM f get
,和liftM
只是fmap
专用于单子)。