Last active
October 3, 2022 00:16
-
-
Save tralamazza/edcc32ccd4f003d89010e924aa428710 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <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"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://cpp.godbolt.org/z/baxaTqWWW