Created
August 6, 2014 22:18
-
-
Save amidvidy/bab48f90480b215b0f51 to your computer and use it in GitHub Desktop.
attempt at Either w/ c++ 11
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// C++11 only | |
#if __cplusplus <= 201103L | |
#include <cstdlib> | |
#include <ctime> | |
#include <iostream> | |
#include <functional> | |
#include <memory> | |
#include <type_traits> | |
namespace functional { | |
template<typename Left, typename Right> | |
struct Either { | |
static_assert(!std::is_same<Left, Right>::value, "Types must be different"); | |
enum State { | |
UNSET, LEFT, RIGHT | |
}; | |
Either() : _state(UNSET) { } | |
explicit Either(const Left& l) : _state(LEFT), _left(new Left(l)) {} | |
explicit Either(const Right& r) : _state(RIGHT), _right(new Right(r)) {} | |
Either(const Either& other) : _state(other._state) { | |
switch (_state) { | |
case LEFT: _left.reset(new Left(*other._left)); break; | |
case RIGHT: _right.reset(new Right(*other._right)); break; | |
case UNSET: break; | |
} | |
} | |
Either(Either&& other) : _state(other._state) { | |
switch (_state) { | |
case LEFT: _left.swap(other._left); break; | |
case RIGHT: _right.swap(other._right); break; | |
case UNSET: break; | |
} | |
} | |
// TODO: make exception safe | |
Either& operator=(const Either& other) { | |
this->~Either(); | |
new (this) Either(other); | |
return *this; | |
} | |
bool isSet() const { return _state != UNSET; } | |
bool isLeft() const { return _state == LEFT; } | |
bool isRight() const { return _state == RIGHT; } | |
template<typename NewLeft, typename NewRight> | |
Either<NewLeft, NewRight> map(std::function<NewLeft(const Left&)> leftF, | |
std::function<NewRight(const Right&)> rightF) const { | |
switch (_state) { // no break needed since all paths return | |
case LEFT: return Either<NewLeft, NewRight>(leftF(*_left)); | |
case RIGHT: return Either<NewLeft, NewRight>(rightF(*_right)); | |
case UNSET: return Either<NewLeft, NewRight>(); | |
} | |
} | |
template<typename NewLeft> | |
Either<NewLeft, Right> bind(std::function<Either<NewLeft, Right>(const Left&)> leftF) { | |
if (isLeft()) { | |
return leftF(*_left); | |
} | |
return Either<NewLeft, Right>(*_right); | |
} | |
const Either& get(std::function<void(const Left&)> leftF, | |
std::function<void(const Right&)> rightF) const { | |
switch (_state) { | |
case LEFT: leftF(*_left); break; | |
case RIGHT: rightF(*_right); break; | |
case UNSET: break; | |
} | |
return *this; | |
} | |
private: | |
std::unique_ptr<Left> _left; | |
std::unique_ptr<Right> _right; | |
const State _state; | |
}; | |
} // functional { | |
int main() { | |
functional::Either<int, std::string> e1; | |
std::srand(std::time(0)); | |
int rand = std::rand(); | |
int toSet = rand % 3; | |
if (toSet == 0) { | |
e1 = functional::Either<int, std::string>(rand); | |
} else if (toSet == 1) { | |
e1 = functional::Either<int, std::string>(std::string("Random number is ") + std::to_string(rand)); | |
} else { | |
/* leave unset */ | |
} | |
e1.map<std::string, int>( | |
[](const int& i) -> std::string { | |
return std::string("My favorite number is ") + std::to_string(i); | |
}, | |
[](const std::string& s) -> int { | |
return s.length(); | |
}) | |
.get( | |
[](const std::string& s) { | |
std::cout << s << std::endl; | |
}, | |
[](const int& i) { | |
std::cout << "Length was: " << i << std::endl; | |
} | |
); | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment