やや異なる種類の状態を持つ状態マシンのファミリーを定義しようとしています。特に、より「複雑な」状態機械には、より単純な状態機械の状態を組み合わせることによって形成される状態があります。
(これは、オブジェクトがオブジェクトでもあるいくつかの属性を持つオブジェクト指向の設定に似ています。)
これが私が達成したいことの簡単な例です。
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
モナドに特化しました)。