Skip to content

Instantly share code, notes, and snippets.

@long-long-float
Created August 2, 2020 16:56
Show Gist options
  • Save long-long-float/1e3a591c6f968377730b8409e65cfa4d to your computer and use it in GitHub Desktop.
Save long-long-float/1e3a591c6f968377730b8409e65cfa4d to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <vector>
#include <algorithm>
#include <list>
using namespace std;
class Object {
public:
virtual ~Object() = default;
};
class Unit : public Object {};
class Context {
vector<shared_ptr<Object>> handlers;
public:
void push_handler(shared_ptr<Object> handler) { handlers.push_back(handler); }
template <class T>
shared_ptr<T> _ () {
for (auto h : handlers) {
if (auto hh = dynamic_pointer_cast<T>(h)) {
return hh;
}
}
return nullptr;
}
template <class T>
T resume(T x, Object* this_, shared_ptr<Object> h) {
handlers.erase(remove_if(handlers.begin(), handlers.end(),
[this_](auto &elem) { return elem.get() == this_; }), handlers.end());
handlers.push_back(h);
return x;
}
};
template <class Out, class In>
class Handler : public Object {
public:
shared_ptr<Context> ctx;
virtual Out return_(In in) = 0;
};
template <class T, class Out, class In>
class Resume : public Object {
virtual Out resume(T x, Handler<Out, In> h) = 0;
};
template <class T, class In>
T with(shared_ptr<Handler<T, In>> handler, std::function<In(shared_ptr<Context>)> f) {
auto ctx = make_shared<Context>();
ctx->push_handler(handler);
handler->ctx = ctx;
try {
auto result = f(ctx);
return ctx->_<Handler<T, In>>()->return_(result);
}
catch(T t) {
return t;
}
}
class Raise : public Object {
public:
virtual void raise(string s) = 0;
};
template <class T>
class DefaultRaise : public Raise, public Handler<T, T> {
T x;
public:
DefaultRaise(T x) : x(x) {}
T return_(T in) { return in; }
void raise(string s) { throw this->x; }
};
int devide(shared_ptr<Context> ctx, int x, int y) {
if (y != 0)
return x / y;
else {
ctx->_<Raise>()->raise("Devision by zero");
return 0;
}
}
void devide_main() {
shared_ptr<Handler<int, int>> dh = make_shared<DefaultRaise<int>>(-1);
int res1 = with<int, int>(dh, [](shared_ptr<Context> ctx) {
return devide(ctx, 4, 2) + 10;
});
cout << "res1 = " << res1 << endl;
int res2 = with<int, int>(dh, [](shared_ptr<Context> ctx) {
return devide(ctx, 4, 0) + 10;
});
cout << "res2 = " << res2 << endl;
shared_ptr<Handler<int, int>> h2 = make_shared<DefaultRaise<int>>(42);
int res3 = with<int, int>(h2, [](shared_ptr<Context> ctx) {
return devide(ctx, 4, 0) + 10;
});
cout << "res3 = " << res3 << endl;
}
template <class T>
class State {
public:
virtual T get() = 0;
virtual Unit put(T x) = 0;
};
template <class T, class U>
class TupleState : public State<T>, public Handler<tuple<T, U>, U> {
T s;
public:
TupleState(T s) : s(s) {}
T get() {
auto h = make_shared<TupleState<T, U>>(s);
h->ctx = this->ctx;
return this->ctx->resume(this->s, this, h);
}
Unit put(T x) {
auto h = make_shared<TupleState<T, U>>(x);
h->ctx = this->ctx;
return this->ctx->resume(Unit(), this, h);
}
tuple<T, U> return_(U x) {
return make_tuple(this->s, x);
}
};
template <class T, class U>
class LogState : public State<T>, public Handler<tuple<list<T>, U>, U> {
list<T> log;
public:
LogState(list<T> log) : log(log) {}
T get() {
auto h = make_shared<LogState<T, U>>(log);
h->ctx = this->ctx;
return this->ctx->resume(this->log.back(), this, h);
}
Unit put(T x) {
list<T> new_log(log);
new_log.push_back(x);
auto h = make_shared<LogState<T, U>>(new_log);
h->ctx = this->ctx;
return this->ctx->resume(Unit(), this, h);
}
tuple<list<T>, U> return_(U x) {
return make_tuple(this->log, x);
}
};
Unit count_down(shared_ptr<Context> ctx) {
int i = ctx->_<State<int>>()->get();
if (i > 0) {
ctx->_<State<int>>()->put(i - 1);
return count_down(ctx);
}
else {
return Unit();
}
}
void count_down_main() {
shared_ptr<Handler<tuple<int, Unit>, Unit>> h1 = make_shared<TupleState<int, Unit>>(2);
auto res1 = with<tuple<int, Unit>, Unit>(h1, [](shared_ptr<Context> ctx) {
return count_down(ctx);
});
cout << "res1 = " << get<0>(res1) << endl;
shared_ptr<Handler<tuple<list<int>, Unit>, Unit>> h2(new LogState<int, Unit>({2}));
auto res2 = with<tuple<list<int>, Unit>, Unit>(h2, [](shared_ptr<Context> ctx) {
return count_down(ctx);
});
cout << "res2 = ";
for (auto e : get<0>(res2)) {
cout << e << ", ";
}
cout << endl;
}
int main() {
cout << "devide" << endl;
devide_main();
cout << "count down" << endl;
count_down_main();
return 0;
}
devide
res1 = 12
res2 = -1
res3 = 42
count down
res1 = 0
res2 = 2, 1, 0,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment