Skip to content

Instantly share code, notes, and snippets.

@jnape
Created December 4, 2020 22:50
Show Gist options
  • Save jnape/847e1c7211469237a4c86e54f8435294 to your computer and use it in GitHub Desktop.
Save jnape/847e1c7211469237a4c86e54f8435294 to your computer and use it in GitHub Desktop.
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <optional>
#include <variant>
#include <any>
template<template<typename, typename> typename CP, typename A, typename B, typename R, template<typename> typename F> concept Coproduct2 =
requires (CP<A,B> cp, F<R(A)> f, F<R(B)> g) {
{ cp.match(f, g) } -> std::same_as<R>;
};
template<template<typename, typename> typename CPO, template<typename, typename> typename CPI, typename A, typename B, typename C, typename R, template<typename> typename F>
concept Coproduct3 = requires {
requires Coproduct2<CPO, A, CPI<B,C>, R, F>;
requires Coproduct2<CPI, B, C, R, F>;
};
template<typename L, typename R>
struct Left {
L l;
template<typename X>
X match(std::function<X(L)> f, std::function<X(R)> g) {
return f(l);
}
};
template<typename L, typename R>
struct Right {
R r;
template<typename X>
X match(std::function<X(L)> f, std::function<X(R)> g) {
return g(r);
}
};
template<template<typename, typename> typename CP, typename A, typename B, typename R>
requires Coproduct2<CP, A, B, R, std::function>
R match(CP<A,B> cp, std::function<R(A)> f, std::function<R(B)> g) {
return cp.match(f, g);
}
template<template<typename, typename> typename CPO, template<typename, typename> typename CPI, typename A, typename B, typename C, typename R>
requires Coproduct3<CPO, CPI, A, B, C, R, std::function>
R match(CPO<A,CPI<B,C>> cpo, std::function<R(A)> f, std::function<R(B)> g, std::function<R(C)> h) {
std::function<R(CPI<B,C>)> gh = [g, h](auto cpi) {
return cpi.match(g, h);
};
return cpo.match(f, gh);
}
template<template<typename, typename> typename CP, typename A, typename B>
requires Coproduct2<CP, A, B, std::optional<A>, std::function>
std::optional<A> projectA(CP<A,B> cp) {
std::function<std::optional<A>(A)> f = [](auto a) {return std::optional(a);};
std::function<std::optional<A>(B)> g = [](auto anything) {return std::optional<A>();};
return match<CP, A, B, std::optional<A>>(cp, f, g);
}
template<template<typename, typename> typename CP, typename A, typename B>
requires Coproduct2<CP, A, B, std::optional<A>, std::function>
std::optional<B> projectB(CP<A,B> cp) {
std::function<std::optional<B>(A)> f = [](auto anything) {return std::optional<B>();};
std::function<std::optional<B>(B)> g = [](auto b) {return std::optional(b);};
return match<CP, A, B, std::optional<B>>(cp, f, g);
}
int main() {
Left<int, std::string> l = Left<int, std::string>{100};
Right<int, std::string> r = Right<int, std::string>{"foo"};
Left<int, Right<std::string, bool>> either = Left<int, Right<std::string, bool>>{3};
std::function<bool(int)> f = [](int x) { return false; };
std::function<bool(std::string)> g = [](auto x) { return true; };
std::function<bool(bool)> h = [](auto x) { return x; };
std::cout << match(either, f, g, h) << std::endl;
std::cout << *(projectA(*(projectB(either)))) << std::endl;
std::cout << *(projectA(l)) << *(projectB(l)) << std::endl;
std::cout << *(projectA(r)) << *(projectB(r)) << std::endl;
std::cout << *(projectA(r)) << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment