Thanks @alice , this is really useful. One pedantic question: why is TryJoin3 not just calling Join3 and then processing after getting the 3 elements ?
Is the sole benefit here to "short circuit" optimization in that the moment one of the 3 gets Err, we stop polling the others ?
In your code above, is there any relation between Try and MaybeDone ? I.e. if you were implementing Join3 instead of Try_Join3, would you still use MaybeDone ?
Intuitively, the answer seems like yes, because it appears the main point of a MaybeDone is to give the option of either taking or not taking the answer.