Skip to content

Instantly share code, notes, and snippets.

@ostollmann
Last active August 29, 2015 14:06
Show Gist options
  • Save ostollmann/0c2d49cd060a8ef3de10 to your computer and use it in GitHub Desktop.
Save ostollmann/0c2d49cd060a8ef3de10 to your computer and use it in GitHub Desktop.
Either monad in C++
#include <iostream>
#include <string>
#include <functional>
#include "either.hxx"
using std::cout;
using std::endl;
using std::string;
using std::function;
int main() {
function<either<string,int>(int)> f = [] (int x) {
if (x == 2) { return either<string,int>::left("Cannot deal with 2."); }
if (x == 12) { return either<string,int>::left("Cannot deal with 12."); }
return either<string,int>::right(x*2);
};
cout << (((Return<string,int>(3) >>= f) >>= f) >>= f) << endl;
// -> <Left:Cannot deal with 12.>
cout << (((Return<string,int>(4) >>= f) >>= f) >>= f) << endl;
// -> <Right:32>
return 0;
}
#ifndef _either_hxx_
#define _either_hxx_
#include <cassert>
#include <ostream>
#include <functional>
using std::ostream;
using std::function;
template<class L,class R>
class either {
public:
static either<L,R> left (L l) { return either(&l,NULL); }
static either<L,R> right(R r) { return either(NULL,&r); }
bool isLeft () const { return (_l != NULL); }
bool isRight() const { return (_r != NULL); }
L fromLeft () const { assert(isLeft ()); return L(*_l); }
R fromRight () const { assert(isRight()); return R(*_r); }
~either() {
if (_l != NULL) delete _l;
if (_r != NULL) delete _r;
}
private:
L* _l; R* _r;
either(const L* l,const R* r) : _l(l != NULL ? new L(*l) : NULL)
, _r(r != NULL ? new R(*r) : NULL) {}
};
template<class L,class R>
ostream& operator<<(ostream& out,const either<L,R> &e) {
if (e.isLeft()) out << "<Left:" << e.fromLeft() << ">";
if (e.isRight()) out << "<Right:" << e.fromRight() << ">";
return out;
}
template<class L,class R1, class R2>
either<L,R2> Bind(either<L,R1> e,function<either<L,R2>(R1)>& f) {
if (e.isLeft()) return either<L,R2>::left(e.fromLeft());
return f(e.fromRight());
}
template<class L,class R>
either<L,R> Return(R r) {
return either<L,R>::right(r);
}
template<class L,class R1,class R2>
either<L,R2> operator>>=(either<L,R1>e,function<either<L,R2>(R1)>&f) {
if (e.isLeft()) return either<L,R2>::left(e.fromLeft());
return f(e.fromRight());
}
#endif
g++ -std=c++11 either.cxx; ./a.out
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment