Lớp MonadReader
được xác định bằng cách sử dụng phần mở rộng FunctionalDependencies
, cho phép khai báo như
class Monad m => MonadReader r m | m -> r where
...
Điều này có nghĩa rằng đối với bất kỳ đơn nguyên m
, các r
được xác định duy nhất bởi nó. Do đó, bạn không thể có một đơn lẻ m
xác định hai loại khác nhau r
. Nếu không có điều này như là một hạn chế, trình biên dịch sẽ không thể đánh dấu việc sử dụng kiểm tra của lớp đó.
Các giải pháp này là để viết các chức năng của bạn như
getA'sInt :: A -> Int
getA'sInt = undefined
getB'sString :: B -> String
getB'sString = undefined
foo :: (MonadReader A m) => m Int
foo = do
a <- asks getA'sInt
return $ a + 1
bar :: (MonadReader B m) => m String
bar = do
b <- asks getB'sString
return $ map toUpper b
Sau đó, chỉ cần sử dụng một tuple (A, B)
trong việc thực hiện thực tế của bạn:
baz :: Reader (A, B) (Int, String)
baz = do
a <- withReader fst foo
b <- withReader snd bar
return (a, b)
Ngoài ra còn có một withReaderT
đối với trường hợp phức tạp hơn.
Như một ví dụ cho lý do tại sao nó không được phép để ngăn xếp ReaderT
s, xem xét các trường hợp
type App = ReaderT Int (Reader Int)
Khi bạn gọi ask
, mà Int
được bạn đề cập đến? Nó có vẻ hiển nhiên rằng đối với trường hợp như
type App = ReaderT A (Reader B)
trình biên dịch sẽ có thể tìm ra để sử dụng, nhưng vấn đề là các ask
chức năng ở đây sẽ có các loại
ask :: App ???
đâu ???
thể là A
hoặc B
. Bạn có thể làm được việc này một cách khác, bằng cách không sử dụng MonadReader
trực tiếp và xác định cụ thể askA
và askB
chức năng:
type App = ReaderT A (Reader B)
askA :: App A
askA = ask
askB :: App B
askB = lift ask
baz :: App (Int, String)
baz = do
a <- askA
b <- askB
return (getA'sInt a, getB'sString b)
Nhưng bạn sẽ chỉ có thể có MonadReader A App
, bạn có thể không còn có MonadReader B App
. Cách tiếp cận này có thể được gọi là "nâng cao rõ ràng", và nó làm cho các chức năng đó đặc trưng cho loại App
và do đó ít có thể tổng hợp hơn.
Oh, 'instance (MonadReader r m) => MonadReader r (ReaderT s m)' thậm chí không tồn tại ?! Tại sao vậy? –