Hãy nói rằng tôi có một monadT:Tại sao bạn không cần sử dụng 'lift' khi tương tác với một monadT lồng nhau StateT trong trường hợp này?
type Wrap a = ReaderT Env (StateT Int (StateT Int Identity)) a
Điều quan trọng cần lưu ý ở đây là một StateT được gói khác, và cả hai đều được bao bọc bên trong một MonadT thứ ba, cụ thể là ReaderT.
và chức năng runWrap tương ứng cho tiện theo dõi:
type Env = Map.Map Char Integer
runWrap :: Env -> Int -> Int -> Wrap a -> a
runWrap env st1 st2 m = runIdentity $ evalStateT (evalStateT (runReaderT m env) st2) st1
Và một đơn nguyên nhà nước tock generic:
tock :: (Num s, MonadState s m) => m()
tock = do modify (+1)
bây giờ tôi tạo ra một monadT bọc nơi bên tôi sử dụng tock:
aWrap :: Wrap (Int, Int)
aWrap = do
lift tock
lift . lift $ tock
x <- get
y <- lift . lift $ get
return (x, y)
Và chạy nó:
env = Map.fromList [('x', 1)]
runWrap env 1 200 aWrap
// answer: (201,2)
Việc sử dụng lift
ở đây có ý nghĩa với tôi về mặt hiểu biết của tôi về cách tương tác với các lớp MonadT lồng nhau.
Tuy nhiên, điều này cũng làm việc và cung cấp cho tôi câu trả lời giống nhau: (201,2)
:
aWrap :: Wrap (Int, Int)
aWrap = do
tock
lift . lift $ tock
x <- get
y <- lift . lift $ get
return (x, y)
Tôi nghĩ rằng bằng cách gọi tock
w/o lift
, nó đọc như thể tock
được áp dụng cho MonadT bên ngoài, cụ thể là ReaderT , không có ý nghĩa gì cả. Nhưng tại sao điều này lại hiệu quả?
P.S. Xin vui lòng bỏ qua sự hiện diện của Env
ở đây, nó không có gì để làm w/câu hỏi, chỉ là sự lựa chọn của MonadT bên ngoài tôi đang sử dụng.