If you were to implement this in a procedural language with side effects, what would you do about "finally"?
A a = new A();
try {
B(a);
return C(a);
} finally {
a.cleanup();
}
Transforms into: Either<Exception, Result> ret;
A a = new A();
ret = B(a);
if (ret.isRight()) ret = C(a);
a.cleanup();
return ret;
Maybe someone can rewrite this even more cleanly. I can think of an easy-to-generate improvement containing a GOTO.I think I prefer the try..catch..finally version - looks much cleaner to me.
finally :: Either err a -> IO () -> (a -> IO (Either err b)) -> IO (Either err b)
finally (Left err) cleanup _k = cleanup >> return (Left err)
finally (Right x) _cleanup k = k x
You avoid having to unwind the stack because the user of finally has to manually convert into CPS in order to supply the higher order argument of type "a -> IO (Either err b)"