answerkey/streamingio/12.answer.md
Let's first consider how attempt interacts with the accessible constructors -- i.e. unit and raiseError:
unit(a).attempt == unit(Right(a))
raiseError(t).attempt == unit(Left(t))
And how handleErrorWith interacts with each constructor:
unit(a).handleErrorWith(h) == unit(a)
raiseError(t).handleErrorWith(h) == h(t)
And how raiseError interacts with flatMap:
raiseError(t).flatMap(f) == raiseError(t)
We could also make some stronger demands on how exceptions are handled. For example, should unit catch exceptions thrown from its thunk argument?
unit(throw new Exception) == raiseError(new Exception)
Should exceptions be caught if thrown from the functions passed to map and flatMap?
fa.map(_ => throw new Exception) == raiseError(new Exception)
fa.flatMap(_ => throw new Exception) == raiseError(new Exception)
There's no wrong answer, only tradeoffs.