Skip to content

Instantly share code, notes, and snippets.

@williamhjcho
Created September 2, 2018 23:22
Show Gist options
  • Save williamhjcho/0f1763785e2abf5a6d8706cf1ba2b349 to your computer and use it in GitHub Desktop.
Save williamhjcho/0f1763785e2abf5a6d8706cf1ba2b349 to your computer and use it in GitHub Desktop.

What is a monad

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

The Maybe Monad

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 value a to a Maybe value type of a
  • >>= :: Maybe a -> (a -> Maybe b) -> Maybe b This takes a Maybe of a, and if possible, sequences the value to b applying a function

What's the point

  1. 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

  1. 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.

  1. Use of effects explicit in types

When writing the operator, it explicitly typed the failure possibility (Nothing) by making it return a Maybe.

  1. 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment