Category Theory for Programmers Chapter 4: Kleisli Categories

Solutions for the challenges in this chapter were basically done as a C++11 file.

#include <iostream>
#include <cmath>
using namespace std;

template<class A>
class optional {
  bool _isValid;
  A _value;
public:
  optional(): _isValid(false) {}
  optional(A v): _isValid(true), _value(v) {}
  bool isValid() const { return _isValid; }
  A value() const { return _value; }
};

optional<double> safe_root(double x) {
  if (x >= 0) return optional<double>(sqrt(x));
  else return optional<double>();
}

// Exercise 1
//
template<class A, class B, class C>
function<optional<C>(A)> compose(
    function<optional<B>(A)> f1,
    function<optional<C>(B)> f2)
{
  return [f1, f2](A x) {
    auto r = f1(x);
    if (r.isValid()) return f2(r.value());
    else return r;
  };
}
template<class A> optional<A> identity(A x) {
  return optional<A>(x);
}

// Exercise 2
//
optional<double> safe_reciprocal(double x) {
  if (x == 0) return optional<double>();
  else return optional<double>(1/x);
}

// Exercise 3
//
optional<double> safe_root_reciprocal(double x) {
  return compose<double,double,double>(safe_root, safe_reciprocal)(x);
}

void test(function<optional<double>(double)> f, double x) {
  cout << "Testing value (" << x << "): ";
  auto r = f(x);
  if (r.isValid()) cout << "Valid (" << r.value() << ")\n";
  else cout << "Not valid\n";
}

int main() 
{
  test(safe_root_reciprocal, -2);
  test(safe_root_reciprocal, 2);
  return 0;
}