문제는 이것입니다. 나는 가지고있다 :mapMonadTrans :: MonadTrans xT => (m a -> n b) -> xT m a -> xT n b
f :: MonadIO m => ReaderT FooBar m Answer;
f = (liftIO getArgs) >>= ...
나는 이것을 수정 된 인수와 함께 실행해야한다. m를 알 수 있기 때문에 나는 모든 m에 대한 m로 (withArgs의 인수를) 변환 어떻게 든 필요가 있기 때문에, 단순히
mapReaderT (withArgs args) :: ReaderT r IO b -> ReaderT r IO b
을 사용할 수 없습니다. 내가 찾은
하나의 가능성은, 따라서, 내 자신의 withArgs을 정의하는 것입니다 : 그러나
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;
};
, 이것은 kludge이며, 하나의 함수에 특정 - 내가해야 모든
withX :: X -> IO a -> IO a
를 다시 쓰기, 예를 들어, Control.Exception.handle
더 좋은 방법은 무엇입니까?
편집 : 핸들의 경우 Control.Monad.CatchIO를 발견했습니다. 다른 경우에는 위의 kludge를 피하기 위해 또 다른, 간결한 kludge (게시 가치가없는)를 사용했습니다. 아직도 더 나은 해결책을 찾고 있습니다!
'f '에서 타입 시그니처를 제거하면 어떨까요? 'MonadIO'에 대한 제약이 너무 제한적인지 궁금합니다. –
'f'에서 입출력을해야합니다. 그렇지 않으면 엄청납니다. (실제로, 타입 b의 값을 얻기위한 함수가있는 데이터 타입 a가 있고, 함수는 a 타입의 일부 값이 I/O를 수행하여 b를 생성 할 수 있도록 충분히 일반적이어야합니다.) –
@strake : Control.Monad.CatchIO에 문제가 있음을 유의하십시오. 즉, 단락 회로 모나드 트랜스포머 (예 : ErrorT)를 사용하는 경우 예상대로 동작하지 않을 수 있습니다. 이것이 설계상의 결함인지 오용인지는 해석이 가능하지만이를 알고 있어야합니다. 자세한 내용은 http://andersk.mit.edu/haskell/monad-peel/를 참조하십시오. –