Given the problem of dividing two numbers:
1 / 2
12 / 512
59 / -123
Seems arbitrarily easy to define a method, or even an operator, for reaching such goal. But there are hidden incumberances when applying mathematical operations with computers, especially dividing by zero.
data Expr = Val Int | Div Expr Expr
This creates a new data type Expr
which could be either a Val
of type Int
, or Div
with two Expr
values.
Now, applying them would simply be
eval :: Expr -> Int
eval (Val n) = n
eval (Div x y) = eval x / eval y
But as is, it could crash the application if given y is zero.
safediv :: Int -> Int -> Maybe Int
safediv n m = if m == 0 then
Nothing
else
Just(n / m)
Now with the check, it won't crash anymore when the second argument is zero.
eval :: Expr -> Maybe Int
eval (Val n) = Just n
eval (Div n m) = case eval x of
Nothing -> Nothing
Just n -> case eval y of
Nothing -> Nothing
Just m -> safediv n / m
Now abstracting the repetition (two instances of case pattern matches)
m >>= f = case m of
Nothing -> Nothing
Just x -> f x
The operator >>=
will apply the function f
for the argument Maybe m
only if it contains a value.
eval :: Expr -> Maybe Int
eval (Val n) = return n
eval (Div n m) = eval n >>= (λx ->
eval m >>= (λy ->
safediv x y))
Now, to make it simpler with the do
notation
eval :: Expr -> Maybe Int
eval (Val n) = return n
eval (Div n m) = do x <- eval x
y <- eval y
safediv x y
It's the Maybe
type and it can be three things:
- It may be anything, a boolean, an integer, etc
return :: a -> Maybe a
This converts a pure valuea
to aMaybe
value type ofa
>>= :: Maybe a -> (a -> Maybe b) -> Maybe b
This takes aMaybe
ofa
, and if possible, sequences the value tob
applying a function
- Same idea works for other effects
It may work for mutable states, I/O, capturing failures (Maybe), reading from environments. What you think of as being effects in programmings languages
- Supports pure programming with effects
It allows the creation/mutation of mutable (impure) states and effects in functions, even in pure programming languages like haskell.
- Use of effects explicit in types
When writing the operator, it explicitly typed the failure possibility (Nothing
) by making it return a Maybe
.
- Functions that work for any effect
For example, a sequence of functions that can have effects, and want to run them one after the other.