다소 다른 종류의 상태로 상태 머신 패밀리를 정의하려고합니다. 특히, 더 "복잡한"상태 머신은 더 단순한 상태 머신의 상태를 결합함으로써 형성된 상태를 갖는다.
(이것은 객체가 객체이기도 한 여러 속성을 갖는 객체 지향 설정과 유사합니다.)
다음은 내가 달성하고자하는 것에 대한 간단한 예입니다.
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
.
StateT InnerState m Int
처음에 어디에서 가치 를 얻 outerStateFoo
습니까?
_innerVal <$> get
그냥gets _innerVal
(로gets f == liftM f get
하고,liftM
그냥fmap
모나드에 전문).