
Anything beyond the Functor instance for (Either e), though, models exceptions that abort the computation as soon as the first Left arises. You seem to use the type in a different way which may be one reason why you do not find your functions implemented elsewhere. For logging or warnings, most Haskellers use something like a writer monad transformer. The underlying monad,
Writer w a = (w,a)
That's the thing I was saying destroys streaming. The problem is that it returns ([log], [a]), instead of [Either log a], so the interleaving has been lost.
Evan, When you say interleaving, do you think of lists like the following? [Left warning1,Right value 1,Left warning 2,Right value2,...] The above is isomorphic to [(warning1,value1),(warning2,value2),...] I don't think that the writer monad destroys streaming. Below is a somewhat contrived, but ordinary use case. {-- begin example --} import Control.Monad.Writer -- from mtl type Log = [String] -- some Monoid half :: Int -> Writer Log Int half x = case x `quotRem` 2 of (y,0) -> return y (y,1) -> writer (y,["Warning: "++(show x)++" was uneven."]) stream :: [Int] stream = 4:8:5:3:7:2: error "broken stream" (ys,warnings) = runWriter (mapM half stream) {-- end example --} ghci> -- load the example above ghci> ys [2,4,2,1,3,1*** Exception: broken stream ghci> mapM_ putStrLn warnings Warning: 5 was uneven. Warning: 3 was uneven. Warning: 7 was uneven. *** Exception: broken stream You see that there is some output before the error is reached, proving that both ys and warnings could be consumed in a streaming manner. Here it is important that the Log monoid's `mappend` function is not strict in the second argument. It would not, for example, work with Log = Data.Sequence.Seq String With mtl you could easily throw in a State monad component that keeps track of the position in the stream, so that warning messages can hint at the place where the warning originated. Olaf