Skip to content

Instantly share code, notes, and snippets.

@tralamazza
Last active October 3, 2022 00:16
Show Gist options
  • Save tralamazza/edcc32ccd4f003d89010e924aa428710 to your computer and use it in GitHub Desktop.
Save tralamazza/edcc32ccd4f003d89010e924aa428710 to your computer and use it in GitHub Desktop.
#include <optional>
// unit/return
static constexpr auto some = [](auto x) { return std::make_optional(x); };
// >>= bind
template <typename T, typename F>
static constexpr std::optional<T> operator>>=(std::optional<T> input, F&& func) {
if (input) {
return func(*input);
} else {
return {};
}
}
// >> bind
template <typename T>
static constexpr auto operator>>(std::optional<T> /*a*/, std::optional<T> b) {
return b;
}
template <typename T, typename F>
static constexpr auto operator>>=(T input, F&& func) {
return func(input);
}
static constexpr auto inc = [](auto a) { return ++a; };
static constexpr auto triple = [](auto a) { return a * 3; };
// https://wiki.haskell.org/Monad_laws
// https://en.wikipedia.org/wiki/Monad_(functional_programming)
// 1. unit is a left-identity for bind:
// unit(x) >>= f <-> f(x)
static_assert((some(0) >>= inc) == inc(0), "Left Identity");
// 2. unit is also a right-identity for bind:
// ma >>= unit <-> ma
static_assert((some(1) >>= some) == some(1), "Right Identity");
// 3. bind is essentially associative:
// ma >>= λx -> (f(x) >>= g) <-> (ma >>= f) >>= g
static_assert(
(some(2) >>= [](auto a) { return inc(a) >>= triple; })
==
((some(2) >>= inc) >>= triple), "Associativity");
static_assert((some(3) >> some(10)) == some(10), "Discard bind");
static_assert(((some(2) >>= inc) >>= triple).value() == 9, "yey");
@tralamazza
Copy link
Author

tralamazza commented Oct 2, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment