Saya mencoba untuk mendefinisikan keluarga mesin negara dengan jenis negara yang agak berbeda. Secara khusus, mesin negara yang lebih "kompleks" memiliki keadaan yang dibentuk dengan menggabungkan keadaan mesin negara yang lebih sederhana.
(Ini mirip dengan pengaturan berorientasi objek di mana objek memiliki beberapa atribut yang juga objek.)
Ini adalah contoh sederhana dari apa yang ingin saya capai.
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
Secara umum, saya ingin kerangka kerja umum di mana sarang ini lebih kompleks. Ini adalah sesuatu yang saya ingin tahu bagaimana melakukannya.
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
Untuk konteks, inilah yang ingin saya capai dengan mesin ini:
Saya ingin merancang hal-hal ini yang disebut "Stream Transformers", yang pada dasarnya adalah fungsi stateful: Mereka mengkonsumsi token, mengubah keadaan internal mereka dan mengeluarkan sesuatu. Khususnya, saya tertarik pada kelas Stream Transformers di mana outputnya adalah nilai Boolean; kami akan memanggil ini "monitor".
Sekarang, saya mencoba merancang kombinator untuk objek-objek ini. Beberapa dari mereka adalah:
- Sebuah
precombinator. Misalkan itumonadalah monitor. Kemudian,pre monadalah monitor yang selalu menghasilkanFalsesetelah token pertama dikonsumsi dan kemudian meniru perilakumonseolah-olah token sebelumnya sedang dimasukkan sekarang. Saya ingin memodelkan keadaanpre mondenganStateWithTriggerdalam contoh di atas karena negara baru adalah boolean bersama dengan keadaan aslinya. - Sebuah
andcombinator. Anggaplahm1danm2monitor. Kemudian,m1 `and` m2adalah monitor yang mengumpan token ke m1, dan kemudian ke m2, dan kemudian menghasilkanTruejika kedua jawaban itu benar. Saya ingin memodelkan keadaanm1 `and` m2denganCombinedStatedalam contoh di atas karena keadaan kedua monitor harus dipertahankan.
StateT InnerState m Intnilai di tempat pertama outerStateFoo?
_innerVal <$> getadilgets _innerVal(sepertigets f == liftM f get, danliftMhanyafmapkhusus untuk monad).