Haskell的嵌套国家

问题描述 投票:3回答:2

我正在尝试定义状态机家族,它们的状态有所不同。特别地,更“复杂”的状态机具有通过组合更简单的状态机的状态而形成的状态。

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

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

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

对于上下文,这是我要使用这种机器实现的目标:

我想设计这些称为“流转换器”的东西,它们基本上是有状态的功能:它们消耗令牌,改变其内部状态并输出某些内容。具体来说,我对一类流转换器感兴趣,该类的输出是布尔值。我们将这些称为“监视器”。

现在,我正在尝试为这些对象设计组合器。其中一些是:

  • A pre组合器。假设mon是监视器。然后,pre mon是一个监视器,它在消耗第一个令牌后始终生成False,然后模仿mon的行为,就像现在正在插入先前的令牌一样。在上面的示例中,我想用pre monStateWithTrigger的状态进行建模,因为新状态和原始状态都是布尔值。
  • and组合器。假设m1m2是监视器。然后,m1 `and` m2是一个监视器,它将令牌馈送给m1,然后馈送给m2,如果两个答案均为真,则产生True。在上面的示例中,我想用m1 `and` m2CombinedState的状态建模,因为必须保持两个监视器的状态。
haskell state monads monad-transformers state-monad
2个回答
1
投票

对于上下文,这是我要使用这种机器实现的目标:

我想设计这些称为“流转换器”的东西,它们基本上是有状态的功能:它们消耗令牌,改变其内部状态并输出某些内容。具体来说,我对一类流转换器感兴趣,该类的输出是布尔值。我们将这些称为“监视器”。

我认为您想要实现的目标不需要太多的机械。

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)

0
投票

关于您的第一个问题,正如卡尔所提到的,zoom中的lens正是您想要的。您的镜头代码可以这样写:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens
import Control.Monad.State.Lazy

newtype InnerState = MkInnerState { _innerVal :: Int }
  deriving (Eq, Ord, Read, Show)

data OuterState = MkOuterState
  { _outerTrigger :: Bool
  , _inner        :: InnerState
  } deriving (Eq, Ord, Read, Show)

makeLenses ''InnerState
makeLenses ''OuterState

innerStateFoo :: Monad m => StateT InnerState m Int
innerStateFoo = do
  i <- gets _innerVal
  put $ MkInnerState (i + 1)
  return i

outerStateFoo :: Monad m =>  StateT OuterState m Int
outerStateFoo = do
  b <- gets _outerTrigger
  if b
    then zoom inner $ innerStateFoo
    else pure 666
© www.soinside.com 2019 - 2024. All rights reserved.