-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Catching errors thrown in the fetch functions #5
Comments
Ok, I dug a little bit into this and the problem is that, fundamentally, errors thrown during interpretation of the free monad cannot be caught by the lifted data ResourceF a
= GetInt (Int -> a)
deriving Functor
program :: FreeT ResourceF (Either String) Int
program = liftF (GetInt id) `catchError` const (pure 1)
result :: Either String Int
result = iterT fetch program -- = Left "error"
where fetch (GetInt next) = throwError "error" The We can solve this by adding a data ResourceF e a
= GetInt (Int -> a)
| Catch a (e -> a)
deriving Functor
getInt :: Monad m => FreeT (ResourceF e) m Int
getInt = liftF (GetInt id)
myCatch :: Monad m => FreeT (ResourceF e) m a -> (e -> FreeT (ResourceF e) m a) -> FreeT (ResourceF e) m a
myCatch m f = wrap (Catch m f)
program :: FreeT (ResourceF String) (Either String) Int
program = getInt `myCatch` \_ -> pure 1
result :: Either String Int
result = iterT fetch program -- = Right 1
where fetch (GetInt next) = throwError "error"
fetch (Catch next f) = catchError next f Now to solve this in fraxl, the question is how do I define a resource that encodes a catch function? |
@ElvishJerricco Any opinion on this? I just came across this library and saw some comments to the effect that you were considering moving some production systems to fraxl. Did that happen, and if so, what exception handling techniques emerged? |
Still trying to wrap my head around this... If we use
liftF x `catchError` f
-- Inline liftF
= (wrap . fmap return) x `catchError` f
-- Inline wrap
= (FreeT $ return $ Free $ fmap return x) `catchError` f
-- inline catchError @FreeT
= FreeT $ liftM (fmap (`catchError` f)) (return $ Free $ fmap return x) `catchError` (runFreeT . f)
-- liftM f (return x) = return (f x)
= FreeT $ return (fmap (`catchError` f) (Free $ fmap return x)) `catchError` (runFreeT . f)
-- return x `catchError` f = return x
= FreeT $ return (fmap (`catchError` f) (Free $ fmap return x))
-- fmap f (return x) = return (f x)
= FreeT $ return (Free $ fmap ((`catchError` f) . return) x)
-- return x `catchError` f = return x
= FreeT $ return (Free $ fmap return x) We see that |
I think it makes sense though. The interpreter isn't throwing to the application code. It's throwing to the toplevel code that called the interpreter. |
So I'd suggest this: Have your data source return data MyReq a where
MightFail :: Args -> MyReq (Either MyError Res)
liftEither :: MonadError e m => Either e a -> m a
liftEither = either throwError return
mightFail :: (MonadFraxl MyReq m, MonadError MyError m) => Args -> m Res
mightFail args = liftEither =<< dataFetch (MightFail args) Note that you cannot use |
I'm trying to understand why using the
catchError
ofFraxl
doesn't catch errors thrown by fetch functions. For example, the following code printsLeft "Error"
instead ofRight 1
:The text was updated successfully, but these errors were encountered: