Skip to content

Instantly share code, notes, and snippets.

@pfultz2
Created November 11, 2014 01:29
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save pfultz2/f538423ebc9bbbe3df92 to your computer and use it in GitHub Desktop.
Save pfultz2/f538423ebc9bbbe3df92 to your computer and use it in GitHub Desktop.
State monad implemented in C++14
#include <utility>
#include <iostream>
struct void_
{
template<typename Stream>
friend Stream &operator<<(Stream &s, void_)
{
return s << "()";
}
};
// yield produces the given value without changing the state.
template<class X>
auto yield(const X& x)
{
return [=](auto s) { return std::make_pair(x, s); };
}
// for_ modifies `m` so that it applies f to its result.
template<class State, class F>
auto for_(State m, F f)
{
return [=](auto r)
{
auto p = m(r);
auto&& x = p.first;
auto&& s = p.second;
return f(x)(s);
};
}
// Examine the state at this point in the computation.
auto get()
{
return [](auto s) { return std::make_pair(s,s); };
}
// Replace the state.
template<class S>
auto put(const S& s)
{
return [=](S) { return std::make_pair(void_(), s); };
}
// Update the state
template<class F>
auto modify(const F& f)
{
return [=](auto s) { return std::make_pair(void_(), f(s)); };
}
template<class X, class Y>
auto do_(X&& x, Y&& y)
{
return for_(x, [=](auto) { return y; });
}
template<class X, class... Xs>
auto do_(X&& x, Xs&&... xs)
{
return do_(x, do_(xs...));
}
template<class Pair>
void print_pair(const Pair& p)
{
std::cout << "(" << p.first << ", " << p.second << ")" << std::endl;
}
int main()
{
auto increment = for_(get(), [](int i)
{
return put(i+1);
});
print_pair(increment(0));
auto postincrement = for_(get(), [](int i)
{
return do_(put(i+1), yield(i));
});
print_pair(postincrement(0));
auto predecrement = for_(get(), [](int i)
{
return do_(put(i-1), get());
});
print_pair(predecrement(1));
auto increment3sq = do_(
increment,
increment,
increment,
for_(get(), [](int i)
{
return yield(i*i);
})
);
print_pair(increment3sq(0));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment