haskell - Haskell 中的嵌套状态

标签 haskell state monads monad-transformers state-monad

我正在尝试定义具有不同类型状态的状态机系列。特别是,更“复杂”的状态机具有通过组合更简单状态机的状态形成的状态。

(这类似于面向对象的设置,其中一个对象具有多个属性,这些属性也是对象。)

这是我想要实现的简化示例。

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

对于上下文,这就是我想用这个机器实现的目标:

我想设计这些叫做“流转换器”的东西,它们基本上是有状态的函数:它们消耗一个 token ,改变它们的内部状态并输出一些东西。具体来说,我对输出为 bool 值的一类流转换器感兴趣;我们将这些称为“监视器”。

现在,我正在尝试为这些对象设计组合器。他们之中有一些是:
  • 一个 pre组合器。假设 mon是显示器。然后,pre mon是一个总是产生 False 的监视器在第一个 token 被消耗然后模仿 mon 的行为之后好像现在正在插入以前的 token 。我想模拟 pre mon 的状态与 StateWithTrigger在上面的示例中,因为新状态与原始状态一起是 bool 值。
  • 一个 and组合器。假设 m1m2是监视器。然后,m1 `and` m2是一个监视器,它将 token 提供给 m1,然后提供给 m2,然后生成 True如果两个答案都是真的。我想模拟 m1 `and` m2 的状态与 CombinedState在上面的示例中,因为必须保持两个监视器的状态。
  • 最佳答案

    For context, this is what I want to achieve with this machinery:

    I want to design these things called "Stream Transformers", which are basically stateful functions: They consume a token, mutate their internal state and output something. Specifically, I am interested in a class of Stream Transformers where the output is a Boolean value; we will call these "monitors".



    我认为你想要达到的目标并不需要太多的机器。
    newtype StreamTransformer input output = StreamTransformer
      { runStreamTransformer :: input -> (output, StreamTransformer input output)
      }
    
    type Monitor input = StreamTransformer input Bool
    
    pre :: Monitor input -> Monitor input
    pre st = StreamTransformer $ \i ->
      -- NB: the first output of the stream transformer vanishes.
      -- Is that OK? Maybe this representation doesn't fit the spec?
      let (_, st') = runStreamTransformer st i
      in  (False, st')
    
    and :: Monitor input -> Monitor input -> Monitor input
    and left right = StreamTransformer $ \i ->
      let (bleft,  mleft)  = runStreamTransformer left  i
          (bright, mright) = runStreamTransformer right i
      in  (bleft && bright, mleft `and` mright)
    

    这个StreamTransformer不一定是有状态的,但承认有状态的。您不需要(而且 IMO 不应该!在大多数情况下!!)为了定义这些类型类(或者确实永远!:),但这是另一个主题)。
    notStateful :: StreamTransformer input ()
    notStateful = StreamTransformer $ \_ -> ((), notStateful)
    
    stateful :: s -> (input -> s -> (output, s)) -> StreamTransformer input output
    stateful s k = StreamTransformer $ \input ->
      let (output, s') = k input s
      in  (output, stateful s' k)
    
    alternateBool :: Monitor anything
    alternateBool = stateful True $ \_ s -> (s, not s)
    

    关于haskell - Haskell 中的嵌套状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59181689/

    相关文章:

    function - 函数 Haskell 的类型推断

    javascript - Array.map 项目到一个状态

    Haskell: 'do [1,2,3]; ["hello"]' 行为说明

    haskell - 简单 Haskell 函数中不断出现(使用FlexibleContexts 来允许此操作)错误

    android - 保存音乐状态

    haskell,如何处理不匹配的类型 - monad

    haskell - 另一种新类型与数据(风格问题)

    haskell - 找到这两组项目的所有可能组合的聪明方法是什么?

    haskell - 为什么这个 Haskell 程序中没有使用尾调用优化?

    reactjs - 在React表单中,为什么我们在输入标签中设置(例如)value={this.state.task}?