Created
December 4, 2020 22:50
-
-
Save jnape/847e1c7211469237a4c86e54f8435294 to your computer and use it in GitHub Desktop.
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
#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