Monads again

Martin Sulzmann

Haskell

We consider the “Maybe” monad.

Functions with implicit side-effects

divInt :: Int -> Int -> Int
divInt _ 0 = error "can't divide by zero"
divInt n m = n `div` m

Making side-effects visible via types

divSafe :: Int -> Int -> Maybe Int
divSafe _ 0 = Nothing
divSafe n m = Just $ n `div` m

Monads

Monads allow for the systematic control of side effects

Maybe is a monad

divSafe2 :: Int -> Int -> Maybe Int
divSafe2 _ 0 = fail ""
divSafe2 n m = return $ n `div` m

Example

-- (x/y)/z
example x y z = case (divSafe x y) of
                  Just res -> case (divSafe res z) of
                                Just res2 -> "Just " ++ show res2
                  Nothing -> "Nothing"

Functional composition to the rescue

exampleM x y z = do res <- divSafe x y
                    res2 <- divSafe res z
                    return res2

-- "do" Syntax desugared in a sequence of "bind" (>>=) operations
-- In our case,
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
exampleM2 x y z =   (divSafe x y)
                     >>=
                    (\res -> divSafe res z
                           >>=
                           (\res -> return res))

Complete source code

import Control.Applicative
import Control.Monad

-- Function with side-effect.
-- We raise an exception if we attempt to divide by zero.
divInt :: Int -> Int -> Int
divInt _ 0 = error "can't divide by zero"
divInt n m = n `div` m

divSafe :: Int -> Int -> Maybe Int
divSafe _ 0 = Nothing
divSafe n m = Just $ n `div` m

-- Maybe is a monad, can use fail/return instead of Nothing/Just.
divSafe2 :: Int -> Int -> Maybe Int
divSafe2 _ 0 = fail ""
divSafe2 n m = return $ n `div` m

example x y z = case (divSafe x y) of
                  Just res -> case (divSafe res z) of
                                Just res2 -> "Just " ++ show res2
                  Nothing -> "Nothing"

exampleM x y z = do res <- divSafe x y
                    res2 <- divSafe res z
                    return res2


-- "do" Syntax desugared in a sequence of "bind" (>>=) operations
-- In our case,
-- (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
exampleM2 x y z =   (divSafe x y)
                     >>=
                    (\res -> divSafe res z
                           >>=
                           (\res -> return res))

runMaybe comp = case comp of
                 Just x -> "The result is: " ++ show x
                 Nothing -> "Failure"


-- Defining our own simple 'maybe' monad

data Res a = Something a | Fail String deriving Show


instance Monad Res where
   return x = Something x
   p >>= f = case p of
              (Fail e) -> Fail e
              (Something x) -> f x

instance Applicative Res where
   pure = return
   x <*> y = do f <- x
                a <- y
                return (f a)

instance Functor Res where
   fmap f x = do a <- x
                 return (f a)

C++

“Maybe” monad in C++

template<typename T>
class Optional {
  bool b;
  T val;
public:
  Optional() : b(false) {}
  Optional(T v) : val(v), b(true) {}
  bool isJust() { return b; }
  bool isNothing() { return !b; }
  T fromJust() { return val; }


  template<typename S>
  Optional<S> bind(function<Optional<S>(T)> f) {
     if (this->isNothing()) {
       return *this;
     } else {
       auto v = this->fromJust();
       return f(v);
     }
  }

  void print() {
      if (this->isNothing()) {
        cout << "\n Invalid result";
      } else {
        cout << "\n" << this->fromJust();
      }
  }

}; // Optional class

template<typename T>
Optional<T> ret(T x) {
    return Optional<T>(x);
}

template<typename T>
Optional<T> fail() {
    return Optional<T>();
}

Compose monad computations via functional composition

Our running example “(x/y)/z” rephrased in terms of C++.

Optional<int> exampleM(int x, int y, int z) {

  return divSafe(x,y).bind<int>([z](int res) -> Optional<int> {
      return divSafe(res,z).bind<int>([](int res2) -> Optional<int> { return ret(res2);});});

}

Method chaining to the resuce

template<typename T>
class Optional {
  Optional<T> div(T x) {
    if (this->isNothing()) {
       return *this;
    } else if(x == 0) {
      return Optional();
    } else {
       auto v = this->fromJust();
       return Optional(v/x);
     }
  }
};
Optional<int> exampleM2(int x, int y, int z) {

  return Optional<int>(x).div(y).div(z);

}

Complete source code

/*

Monads. A concept none in functional languages such as Haskell.
Turns out, monads are also useful in imperative languages.

- Systematic control of side effects.
- We use types to describe effects.
- Effectful computations are built via function composition.

Benefits.

Systematic control of side effects.
What and where side effects take place can be easily read out of the program text.

User needs to follow the "monadic" design pattern.


Example: The Optional (aka Maybe) monad.

Side effect we wish to control:
    Result is successful ("just some value") or fails ("nothing").

*/


#include <functional>
#include <stdio.h>
#include <iostream>
using namespace std;


// Haskell's Maybe rephrased in C++.
template<typename T>
class Optional {
  bool b;
  T val;
public:
  Optional() : b(false) {}
  Optional(T v) : val(v), b(true) {}
  bool isJust() { return b; }
  bool isNothing() { return !b; }
  T fromJust() { return val; }


  // function<Optional<S>(T)> represents a function
  // T -> Optional<S>
  template<typename S>
  Optional<S> bind(function<Optional<S>(T)> f) {
     if (this->isNothing()) {
       return *this;
     } else {
       auto v = this->fromJust();
       return f(v);
     }
  }

  void print() {
      if (this->isNothing()) {
        cout << "\n Invalid result";
      } else {
        cout << "\n" << this->fromJust();
      }
  }

  // Assumes type T supports division.
  Optional<T> div(T x) {
    if (this->isNothing()) {
       return *this;
    } else if(x == 0) {
      return Optional();
    } else {
       auto v = this->fromJust();
       return Optional(v/x);
     }
  }
}; // Optional class

template<typename T>
Optional<T> ret(T x) {
    return Optional<T>(x);
}

template<typename T>
Optional<T> fail() {
    return Optional<T>();
}


// Fail safe integer division

Optional<int> divSafe(int x, int y) {
  if (y == 0) {
    return Optional<int>();
  } else {
    return Optional<int>(x / y);
  }
}

// (x/y)/z

Optional<int> example(int x, int y, int z) {

  auto res = divSafe(x,y);
  if (res.isNothing()) {
    cout << "\n Invalid result";
  }
  auto res2 = divSafe(res.fromJust(),z);

  return res2;

}


// Optional is a monad.
// Use functional composition.

Optional<int> exampleM(int x, int y, int z) {

  return divSafe(x,y).bind<int>([z](int res) -> Optional<int> {
      return divSafe(res,z).bind<int>([](int res2) -> Optional<int> { return ret(res2);});});

}

// Method chaining instead of functional composition.
Optional<int> exampleM2(int x, int y, int z) {

  return Optional<int>(x).div(y).div(z);

}



int main() {
  int x,y,z;
  x = 12; y = 2; z = 3;
  example(x,y,z).print();

  exampleM(x,y,z).print();

  exampleM2(x,y,z).print();


}