#pragma once

#include <functional>
#include <utility>

namespace Xybrid::Util {
    // example implementation from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0200r0.html adjusted for style
    template <class F>
    class YCombinator {
        F f_; // base lambda
    public:
        template<class T> explicit YCombinator(T&& f) : f_(std::forward<T>(f)) {}

        template<class... Args> decltype(auto) operator()(Args&&... args) {
            return f_(std::ref(*this), std::forward<Args>(args)...); // pass self into base along with args
        }
    };
    template<class F> decltype(auto) yCombinator(F&& f) { return YCombinator<std::decay_t<F>>(std::forward<F>(f)); }
}
