Tôi đang cố gắng xác định một họ các máy trạng thái với các loại trạng thái khác nhau. Cụ thể, các máy trạng thái "phức tạp" hơn có các trạng thái được hình thành bằng cách kết hợp các trạng thái của các máy trạng thái đơn giản hơn.
(Điều này tương tự với cài đặt hướng đối tượng trong đó một đối tượng có một số thuộc tính cũng là đối tượng.)
Dưới đây là một ví dụ đơn giản về những gì tôi muốn đạt được.
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
Tổng quát hơn, tôi muốn một khung tổng quát nơi các tổ này phức tạp hơn. Đây là một cái gì đó tôi muốn biết làm thế nào để làm.
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
Đối với bối cảnh, đây là những gì tôi muốn đạt được với máy móc này:
Tôi muốn thiết kế những thứ gọi là "Stream Transformers", về cơ bản là các chức năng trạng thái: Chúng tiêu thụ một mã thông báo, làm thay đổi trạng thái bên trong của chúng và tạo ra thứ gì đó. Cụ thể, tôi quan tâm đến một lớp Stream Transformers trong đó đầu ra là giá trị Boolean; chúng tôi sẽ gọi những "màn hình" này.
Bây giờ, tôi đang cố gắng thiết kế tổ hợp cho các đối tượng này. Một số trong số họ là:
- Một
pre
tổ hợp. Giả sử đómon
là một màn hình. Sau đó,pre mon
là một màn hình luôn tạo raFalse
sau khi mã thông báo đầu tiên được tiêu thụ và sau đó bắt chước hành vimon
như thể mã thông báo trước đó đang được chèn ngay bây giờ. Tôi muốn mô hình hóa trạng tháipre mon
vớiStateWithTrigger
trong ví dụ trên vì trạng thái mới là boolean cùng với trạng thái ban đầu. - Một
and
tổ hợp. Giả sử rằngm1
vàm2
là màn hình. Sau đó,m1 `and` m2
là một màn hình cung cấp mã thông báo cho m1, sau đó đến m2 và sau đó tạo raTrue
nếu cả hai câu trả lời là đúng. Tôi muốn mô hình hóa trạng tháim1 `and` m2
vớiCombinedState
trong ví dụ trên vì trạng thái của cả hai màn hình phải được duy trì.
StateT InnerState m Int
giá trị ở nơi đầu tiên ở outerStateFoo
?
_innerVal <$> get
chỉ làgets _innerVal
(nhưgets f == liftM f get
, vàliftM
chỉfmap
chuyên về các đơn nguyên).