Skip to content

Instantly share code, notes, and snippets.

@momento-potsi
Created January 26, 2021 04:26
Show Gist options
  • Save momento-potsi/37c039dc06311e15ba5bbb61eb0d9514 to your computer and use it in GitHub Desktop.
Save momento-potsi/37c039dc06311e15ba5bbb61eb0d9514 to your computer and use it in GitHub Desktop.
why
enum class Unit {
Unit
};
template <typename A, typename Fn = std::function<A()>>
struct IO {
Fn runIO {};
A operator()() const { return runIO(); }
};
template <typename T> struct unIO {};
template <typename T> struct unIO<IO<T>> { using type = T; };
template <typename T> using unIO_t = unIO<T>::type;
auto const putChar = [](char c) -> IO<Unit> {
return {[c]() { std::cout << c; return Unit::Unit; }};
};
auto const putStr = [](std::string const& s) -> IO<Unit> {
return {[s]() { std::cout << s; return Unit::Unit; }};
};
auto const fmap = []<typename Fn, typename A, typename B = std::invoke_result_t<Fn,A>>(Fn f, IO<A> ma) -> IO<B> {
return {[f, ma]() { return f(ma()); }};
};
auto const pure = []<typename A>(A a) -> IO<A> {
return {[a]() { return a; }};
};
auto const ap = []<typename Fn, typename A, typename B = std::invoke_result_t<Fn,A>>(IO<Fn> mf, IO<A> ma) -> IO<B> {
return {[mf, ma]() { return mf()(ma()); }};
};
auto const id = []<typename T>(T x) -> T {
return x;
};
auto const then = []<typename A, typename B>(IO<A> ma, IO<B> mb) -> IO<B> {
return ap(fmap([](auto x) { return id; }, ma), mb);
};
auto const putStrLn = [](std::string const& s) -> IO<Unit> {
return then(putStr(s), putChar('\n'));
};
template <typename T>
IO<T> const readLn {[]() { T result {}; std::cin >> result; return result; }};
auto const bind = []<typename Fn, typename A, typename B = unIO_t<std::invoke_result_t<Fn,A>>>(IO<A> ma, Fn f) -> IO<B> {
return {[ma, f]() { return f(ma())(); }};
};
int main() {
bind(readLn<std::string>, putStrLn)();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment