That's the premise of the article and it is demonstrably false. You throw exceptions in a reproducible manner based on input, not a RNG!
function oneDividedByX(x: Double): Double
oneDividedByX(2) // 1/2
oneDividedByX(3) // 1/3
and so on.. Except with zero. With zero you get an exception, however nothing in function signature mentions about such result. You only expect a double
In Either case - it solves the problem, because the signature would be like this:
function oneDividedByX(x: Double): Either[ComputingError, Double]
As for throwing exceptions - it can be done in pure way, but catching exceptions cannot