如何在Haskell中处理postRetweet函数的单条推文转发异常?
Got it, let's fix this step by step. Your original function fails entirely when a single retweet throws an exception—here's how to use try to handle each retweet's errors individually without breaking the whole batch:
First, let's adjust the function's return type to capture both success and failure states. Instead of returning IO [Status], we'll return IO [Either SomeException Status]—this way, each entry in the list will be either a successful Status (wrapped in Right) or a caught exception (wrapped in Left).
Here's the revised code, with explanations of key changes:
-- Make sure to import these modules first import Control.Exception (SomeException, try) import Control.Lens ((^.)) import Data.Text (pack) -- Keep your existing imports for TweetIdStr, Status, Response, authenticate, retweetUrl, etc. postRetweet :: IO [TweetIdStr] -> IO [Either SomeException Status] postRetweet tweetIdsIO = do -- Extract the list of Tweet IDs from the IO action first (simpler than nested >>=) tweetIds <- tweetIdsIO -- For each ID, attempt the retweet and catch any exceptions -- `try` wraps the IO action to return Either Exception Result instead of throwing responseAttempts <- mapM (\tid -> try $ postWith authenticate (retweetUrl ++ tid ++ ".json") (pack "ABC")) tweetIds -- Convert successful responses to Status values (using your original lens access) -- Failures stay as Left SomeException pure $ map (fmap (^. responseStatus)) responseAttempts
Key Changes Explained:
- Signature Update: The return type now uses
Either SomeException Statusto track per-retweet outcomes. This prevents a single failure from taking down the entire batch. - Per-Request Exception Handling: We wrap each individual
postWithcall withtry—this catches exceptions for that specific retweet instead of letting them propagate up and stop processing. - Simplified IO Binding: Instead of chaining
>>=nested lambdas, we first extract the list of tweet IDs from the inputIOaction to make the code easier to read. - Result Transformation: We use
fmap (^. responseStatus)on eachEitherresult to convert successfulResponsevalues (frompostWith) to theStatustype you need, while leaving exceptions untouched.
Optional: Target Specific Exceptions
If you know exactly what type of exception postWith throws (e.g., HttpException from network-http-client), you can replace SomeException with that specific type for more precise error handling. For example:
import Network.HTTP.Client (HttpException) postRetweet :: IO [TweetIdStr] -> IO [Either HttpException Status] postRetweet tweetIdsIO = do tweetIds <- tweetIdsIO responseAttempts <- mapM (\tid -> try $ postWith authenticate (retweetUrl ++ tid ++ ".json") (pack "ABC")) tweetIds pure $ map (fmap (^. responseStatus)) responseAttempts
This way, you only catch the exceptions you expect, instead of all possible exceptions.
内容的提问来源于stack exchange,提问作者Alexia Desouza

