fork download
  1. #include <iostream>
  2. #include <string>
  3. #include <tuple>
  4. #include <boost/variant.hpp>
  5. using namespace std;
  6.  
  7. class Value {
  8. int x;
  9. public:
  10. explicit Value(int x) : x(x) {}
  11. Value(Value&&) = default;
  12. Value(const Value&) = delete;
  13.  
  14. friend ostream& operator << (ostream& ost, const Value& v) {
  15. return ost << v.x;
  16. }
  17.  
  18. int copy() const { return x; }
  19. int take()&& { int y = x; x = 100500; return y; }
  20. };
  21.  
  22. Value operator ~(Value v) {
  23. return Value(-move(v).take());
  24. }
  25. Value operator *(Value a, Value b) {
  26. return Value(move(a).take() * move(b).take());
  27. }
  28.  
  29.  
  30. using Trace = tuple<Value, string>;
  31.  
  32. ostream& operator << (ostream& ost, const Trace& t) {
  33. return ost << get<0>(t) << " = " << get<1>(t);
  34. }
  35.  
  36. Trace trace(Value v) {
  37. string s = to_string(v.copy());
  38. return Trace{move(v), move(s)};
  39. }
  40.  
  41. Trace tkonst(int x) {
  42. return trace(Value(x));
  43. }
  44.  
  45. Trace operator ~(Trace t) {
  46. return Trace{
  47. ~move(get<0>(t)),
  48. "~(" + get<1>(t) + ")"
  49. };
  50. }
  51. Trace operator *(Trace a, Trace b) {
  52. return Trace{
  53. move(get<0>(a)) * move(get<0>(b)),
  54. "(" + get<1>(a) + ")*(" + get<1>(b) + ")"
  55. };
  56. }
  57.  
  58. using Either = boost::variant<Trace, string>;
  59. Either&& emove(Either& e) { return static_cast<Either&&>(e); }
  60.  
  61. bool ok(const Either& e) {
  62. return boost::get<Trace>(&e) != nullptr;
  63. }
  64.  
  65. Trace move_then(Either& e) {
  66. return boost::get<Trace>(emove(e));
  67. }
  68. const Trace& peek_then(const Either& e) {
  69. return boost::get<Trace>(e);
  70. }
  71.  
  72. string move_else(Either& e) {
  73. return boost::get<string>(emove(e));
  74. }
  75. const string& peek_else(const Either& e) {
  76. return boost::get<string>(e);
  77. }
  78.  
  79. ostream& operator << (ostream& ost, const Either& e) {
  80. return ok(e) ? (ost << "THEN " << peek_then(e))
  81. : (ost << "ELSE " << peek_else(e));
  82. }
  83.  
  84. Either good(Trace t) {
  85. return t;
  86. }
  87. Either error(string s) {
  88. return s;
  89. }
  90. Either ekonst(int x) {
  91. return good(trace(Value(x)));
  92. }
  93.  
  94. Either operator ~(Either e) {
  95. if (!ok(e)) return e;
  96. return good(~move_then(e));
  97. }
  98. Either operator *(Either a, Either b) {
  99. if (!ok(a)) return a;
  100. if (!ok(b)) return b;
  101. return good(move_then(a) * move_then(b));
  102. }
  103. Either operator |(Either a, Either b) {
  104. if (ok(a)) return a;
  105. if (ok(b)) return b;
  106. return error(move_else(a) + " | " + move_else(b));
  107. }
  108.  
  109. template<class F> struct Lazy { F f; };
  110.  
  111. template<class F> auto lazy(F f) { return Lazy<F>{f}; }
  112.  
  113. template<class F> auto run(Lazy<F> f)->Either { return f.f(); }
  114.  
  115. template<class F> auto operator ~(Lazy<F> f) {
  116. return lazy([f]()->Either { return ~run(f); });
  117. }
  118. template<class F, class G> auto operator *(Lazy<F> f, Lazy<G> g) {
  119. return lazy([f, g]()->Either {
  120. Either a = run(f);
  121. if (!ok(a)) return a;
  122. return emove(a) * run(g);
  123. });
  124. }
  125. template<class F, class G> auto operator |(Lazy<F> f, Lazy<G> g) {
  126. return lazy([f, g]()->Either {
  127. Either a = run(f);
  128. if (ok(a)) return a;
  129. return emove(a) | run(g);
  130. });
  131. }
  132.  
  133. auto will_eval(int x) {
  134. return lazy([x]() {
  135. cout << "evaluating " << x << "..." << endl;
  136. return ekonst(x);
  137. });
  138. }
  139.  
  140. auto will_fail(string s) {
  141. return lazy([s]() {
  142. cout << "failing " << s << "..." << endl;
  143. return error(s);
  144. });
  145. }
  146.  
  147. int main() {
  148. cout << run(will_eval(123) * ~will_eval(456) | ~will_eval(789) * will_eval(100500)) << endl;
  149. cout << run(will_eval(123) * will_fail("ahaha")) << endl;
  150. cout << run(will_fail("ohoho") | will_fail("ehehe")) << endl;
  151. }
Success #stdin #stdout 0s 4504KB
stdin
Standard input is empty
stdout
evaluating 123...
evaluating 456...
THEN -56088 = (123)*(~(456))
evaluating 123...
failing ahaha...
ELSE ahaha
failing ohoho...
failing ehehe...
ELSE ohoho | ehehe