ฉันกำลังพยายามกำหนดตระกูลของเครื่องสถานะที่มีสถานะแตกต่างกันบ้าง โดยเฉพาะอย่างยิ่งยิ่งเครื่องจักรซับซ้อน "รัฐ" มีสถานะที่เกิดขึ้นจากการรวมรัฐของเครื่องจักรรัฐง่ายขึ้น
(สิ่งนี้คล้ายกับการตั้งค่าวัตถุที่วัตถุมีหลายคุณลักษณะที่เป็นวัตถุด้วย)
นี่คือตัวอย่างที่เรียบง่ายของสิ่งที่ฉันต้องการบรรลุ
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
ในตัวอย่างข้างต้นเนื่องจากสถานะใหม่เป็นบูลีนพร้อมกับสถานะดั้งเดิม and
Combinator สมมติว่า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)