EAFP in Haskell
I have doubts about the capabilities and types, and their hypothetical relation to EAFP (easier to apologize to permission). I've worked with Python and got used to working with the EAFP paradigm in the world of exceptions.
Classic example: Division by zero
def func(x,y):
if not y:
print "ERROR."
else: return (x/y)
and Python style:
def func(x,y):
try:
return (x/y)
except: return None
In Haskell, the first function would be
func :: (Eq a, Fractional a) => a -> a -> a
func x y = if y==0 then error "ERROR." else x/y
and with Maybe:
func :: (Eq a, Fractional a) => a -> a -> Maybe a
func x y = if y==0 then Nothing else Just (x/y)
In the Python version, you run func
without checking y
. With Haskell, the story is the opposite: it is checked y
.
My question is:
- Formally, does Haskell support the EAFP paradigm, or does it "prefer" LBYL while allowing for a semi-ghostly approximation of EAFP?
PD: I called it "semi-natural" because even if it's intuitively readable, it looks (to me at least) like the EAFP vulnerability.
source to share
Haskell style with Maybe
and Either
forces you to check for an error at some point, but it shouldn't be right away. If you don't want to deal with this error now, you can simply propagate it to the rest of your computation.
Taking your hypothetical example of safe division by -0, you can use it in a broader computation without explicit checking:
do result <- func a b
let x = result * 10
return x
Here, you don't need to match Maybe
, the returned one func
: you just extract it into a variable result
using do-notation, which is automatically propagated to the whole system. The consequence of this is that you don't need to address the potential error immediately, but the final result of the calculation is wrapped in Maybe
.
This means that you can easily combine (create) functions that lead to an error without checking the error at every step.
In a way, it gives you the best of both worlds. You still only have to check for errors in one place, at the very end, but you are explicit about that. You must use something like do-notation to take care of the actual propagation, and you cannot ignore the final error by accident: if you don't want to handle it, you must explicitly turn it into a runtime error.
Is not explicit better than implicit?
Haskell now also has an exception system for dealing with runtime errors that you don't need to check at all. This is useful sometimes, but not too often. In Haskell, we only use it for errors, which we don't expect to ever expect. The rule of thumb is that a runtime exception represents an error in your program, while incorrect input or just an unusual case should be presented Maybe
or Either
.
source to share