ฉันกำลังพยายามกำหนดตระกูลของเครื่องสถานะที่มีสถานะแตกต่างกันบ้าง โดยเฉพาะอย่างยิ่งยิ่งเครื่องจักรซับซ้อน "รัฐ" มีสถานะที่เกิดขึ้นจากการรวมรัฐของเครื่องจักรรัฐง่ายขึ้น
(สิ่งนี้คล้ายกับการตั้งค่าวัตถุที่วัตถุมีหลายคุณลักษณะที่เป็นวัตถุด้วย)
นี่คือตัวอย่างที่เรียบง่ายของสิ่งที่ฉันต้องการบรรลุ
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
สำหรับบริบทนี่คือสิ่งที่ฉันต้องการบรรลุด้วยเครื่องจักรนี้:
ฉันต้องการออกแบบสิ่งเหล่านี้เรียกว่า "สตรีม Transformers" ซึ่งโดยทั่วไปแล้วเป็นหน้าที่ของรัฐ: พวกเขาใช้โทเค็นเปลี่ยนสถานะภายในและส่งออกบางอย่าง โดยเฉพาะฉันสนใจในคลาสของ Stream Transformers ที่เอาต์พุตเป็นค่าบูลีน เราจะเรียก "จอภาพ" เหล่านี้
ตอนนี้ฉันพยายามออกแบบ combinators สำหรับวัตถุเหล่านี้ บางส่วนของพวกเขาคือ:
- เครื่องคอม
preบิเนเตอร์ สมมติว่าmonเป็นจอภาพ จากนั้นpre monเป็นจอมอนิเตอร์ที่สร้างเสมอFalseหลังจากที่โทเค็นแรกถูกใช้ไปแล้วจะเลียนแบบพฤติกรรมของmonราวกับว่าโทเค็นก่อนหน้านี้ถูกแทรกอยู่ตอนนี้ ฉันต้องการสร้างแบบจำลองสถานะpre monด้วยStateWithTriggerในตัวอย่างข้างต้นเนื่องจากสถานะใหม่เป็นบูลีนพร้อมกับสถานะดั้งเดิม andCombinator สมมติว่าm1และm2เป็นจอภาพ จากนั้นm1 `and` m2เป็นจอภาพที่ป้อนโทเค็นไปยัง m1 และจากนั้นไปที่ m2 จากนั้นสร้างTrueหากคำตอบทั้งคู่เป็นจริง ฉันต้องการสร้างแบบจำลองสถานะm1 `and` m2ด้วยCombinedStateในตัวอย่างด้านบนเนื่องจากต้องรักษาสถานะของจอภาพทั้งสอง
StateT InnerState m Intคุ้มค่าในสถานที่แรกในouterStateFooที่ไหน?
_innerVal <$> getเป็นเพียงgets _innerVal(ตามgets f == liftM f getและliftMเป็นเพียงfmapความเชี่ยวชาญในการ monads)