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
pre
combinator. Misalkan itumon
adalah monitor. Kemudian,pre mon
adalah monitor yang selalu menghasilkanFalse
setelah token pertama dikonsumsi dan kemudian meniru perilakumon
seolah-olah token sebelumnya sedang dimasukkan sekarang. Saya ingin memodelkan keadaanpre mon
denganStateWithTrigger
dalam contoh di atas karena negara baru adalah boolean bersama dengan keadaan aslinya. - Sebuah
and
combinator. Anggaplahm1
danm2
monitor. Kemudian,m1 `and` m2
adalah monitor yang mengumpan token ke m1, dan kemudian ke m2, dan kemudian menghasilkanTrue
jika kedua jawaban itu benar. Saya ingin memodelkan keadaanm1 `and` m2
denganCombinedState
dalam contoh di atas karena keadaan kedua monitor harus dipertahankan.
StateT InnerState m Int
nilai di tempat pertama outerStateFoo
?
_innerVal <$> get
adilgets _innerVal
(sepertigets f == liftM f get
, danliftM
hanyafmap
khusus untuk monad).