Vấn đề là vấn đề này. Tôi có:mapMonadTrans :: MonadTrans xT => (m a -> n b) -> xT m a -> xT n b
f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...
Tôi cần chạy điều này với các đối số đã sửa đổi. Tuy nhiên, vì m là không rõ, tôi có thể không chỉ đơn giản là sử dụng
mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b
kể từ khi tôi cần bằng cách nào đó để transform (withArgs args) vào m cho tất cả m.
Một khả năng tôi thấy là xác định withArgs của riêng tôi, như sau:
import System.Environment (setArgs, freeArgv);
withArgv new_args act = do {
pName <- liftIO System.Environment.getProgName;
existing_args <- liftIO System.Environment.getArgs;
bracket (liftIO $ setArgs new_args)
(\argv -> do {
_ <- liftIO $ setArgs (pName:existing_args);
liftIO $ freeArgv argv;
})
(const act);
};
withArgs xs act = do {
p <- liftIO System.Environment.getProgName;
withArgv (p:xs) act;
};
Tuy nhiên, đây là một kludge, và cụ thể cho một chức năng - Tôi sẽ cần phải viết lại mỗi withX :: X -> IO a -> IO a
, ví dụ Control.Exception.handle
Điều gì, nếu có, là cách tốt hơn để làm điều này?
Chỉnh sửa: Trong trường hợp xử lý, tôi tìm thấy Control.Monad.CatchIO. Trong trường hợp khác, tôi đã sử dụng một cái khác, briefer kludge (không đáng để đăng) để tránh kludge ở trên. Vẫn đang tìm kiếm một giải pháp tốt hơn!
Điều gì xảy ra nếu bạn xóa chữ ký loại trên 'f'? Tôi tự hỏi nếu ràng buộc với 'MonadIO' là quá hạn chế. –
Tôi cần làm I/O trong 'f'. Nếu không, đó sẽ là lớn. (Trong thực tế, tôi có một kiểu dữ liệu a với một hàm trong nó để mang lại một số giá trị của loại b, và hàm phải đủ chung để một số giá trị của kiểu a có thể làm I/O để sinh lợi b.) –
@strake : lưu ý rằng có sự cố với Control.Monad.CatchIO. Cụ thể là, nếu bạn đang sử dụng một máy biến áp ngắn mạch (ví dụ: ErrorT), nó có thể cho nó không hoạt động như bạn mong đợi. Cho dù đây là một lỗ hổng thiết kế hoặc lạm dụng được mở để giải thích, nhưng bạn nên nhận thức được nó. Xem http://andersk.mit.edu/haskell/monad-peel/ để biết chi tiết. –