Skip to content

Instantly share code, notes, and snippets.

@mxswd
Last active December 28, 2015 07:49
Show Gist options
  • Save mxswd/7466974 to your computer and use it in GitHub Desktop.
Save mxswd/7466974 to your computer and use it in GitHub Desktop.
#include <tr1/type_traits>
#include <iostream>
#include <vector>
#include <algorithm>
// (* -> *) -> Constraint
template<template <typename> class T>
class Functor {
public:
template <typename A, typename B>
static T<B> fmap(const T<A> &, typename std::tr1::add_pointer<B(A)>::type);
};
// (* -> *) -> Constraint
template<template <typename> class M>
class Monad {
public:
template <typename T>
static M<T> returnM(const T&);
template <typename T, typename U>
static M<U> bindM(const M<T>&, typename std::tr1::add_pointer<M<U>(T)>::type);
};
// * -> *
template<typename T>
struct Maybe {
bool nothing;
T just;
static Maybe<T> Just(T a) {Maybe<T> p; p.nothing = false; p.just = a; return p;};
static Maybe<T> Nothing() {Maybe<T> p; p.nothing = true; return p;};
T getOrElse(const T &a) {
if (nothing)
return a;
else
return just;
}
};
template <>
struct Functor<Maybe> {
template<typename A, typename B>
static Maybe<B> fmap(const Maybe<A> &a, typename std::tr1::add_pointer<B(A)>::type fp) {
Maybe<B> b;
if (!(b.nothing = a.nothing)) {
b.just = fp(a.just);
}
return b;
}
};
template <>
struct Monad<Maybe> {
template<typename T>
static Maybe<T> returnM(const T& v) {
return Maybe<T>::Just(v);
}
template<typename T, typename U>
static Maybe<U> bindM(const Maybe<T>& m, typename std::tr1::add_pointer<Maybe<U>(T)>::type fp) {
if (m.nothing)
return m;
else
return fp(m.just);
}
};
template <typename T>
using vector = std::vector<T>;
template <>
struct Functor<vector> {
template<typename A, typename B>
static std::vector<B> fmap(const std::vector<A> &a, typename std::tr1::add_pointer<B(A)>::type fp) {
for_each(a.begin(), a.end(), fp);
return a;
}
};
template <typename A>
A identity(const A&a) { return a; }
int main() {
std::cout << "fmap" << std::endl;
std::vector<Maybe<int>> v;
v.push_back(Maybe<int>::Just(1));
v.push_back(Maybe<int>::Nothing());
v.push_back(Maybe<int>::Just(3));
v.push_back(Maybe<int>::Nothing());
for_each(v.begin(), v.end(), [](Maybe<int> a) -> Maybe<int> {
return Functor<Maybe>::fmap<int, int>(a, [](int b) -> int {
std::cout << b << std::endl;
return 0;
});
});
// vector
std::cout << "vector" << std::endl;
std::vector<int> q;
q.push_back(1);
q.push_back(2);
q.push_back(3);
q.push_back(4);
q.push_back(5);
auto plusOne = [](int b) -> int {
std::cout << b << std::endl;
return b + 1;
};
auto oddVals = [](int x) -> Maybe<int> {
if (x % 2 == 1)
return Maybe<int>::Just(x);
else
return Maybe<int>::Nothing();
};
Functor<vector>::fmap<int, int>(q, plusOne);
// Functor<vector>::fmap<int, Maybe<int>>(q, oddVals);
std::cout << "monad" << std::endl;
auto doubleIfOdd = [](int x) -> Maybe<int> {
std::cout << x << std::endl;
if (x % 2 == 1)
return Maybe<int>::Just(x * 2);
else
return Maybe<int>::Nothing();
};
Maybe<int> x1 = Monad<Maybe>::returnM(1);
Maybe<int> x2 = Monad<Maybe>::bindM<int, int>(x1, doubleIfOdd);
Maybe<int> x3 = Monad<Maybe>::bindM<int, int>(x2, doubleIfOdd);
std::cout << x3.getOrElse(9001) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment