261.md
September 5, 2022 ยท View on GitHub
Example
int main() {
auto opt = std::optional{42};
opt.and_then([](auto o)->std::optional<int>{ std::cout << o;; return std::nullopt; });// prints 42
}
Puzzle
- Can you refactor
executeroutine with monadic Monadic operations?
struct market_data{};
struct trade{};
struct order{};
struct order_with_id{};
std::optional<order_with_id> execute(auto& ts, const market_data& md) {
auto trade = ts.parse(md);
if (not trade) {
return std::nullopt;
}
auto order = ts.model(*trade);
if (not order) {
return std::nullopt;
}
if (auto order_with_id = ts.map(*order)) {
return order_with_id;
} else {
return std::nullopt;
}
}
int main(){
using namespace boost::ut;
should("produce bail out on market data") = [] {
struct {
auto parse(const market_data&) -> std::optional<trade> { return {}; }
auto model(const trade&) -> std::optional<order> { return {{}}; }
auto map(const order&) -> std::optional<order_with_id> { return {{}}; }
} fake_ts;
expect(not execute(fake_ts, {}).has_value());
};
should("produce bail out on model") = [] {
struct {
auto parse(const market_data&) -> std::optional<trade> { return {{}}; }
auto model(const trade&) -> std::optional<order> { return {}; }
auto map(const order&) -> std::optional<order_with_id> { return {{}}; }
} fake_ts;
expect(not execute(fake_ts, {}).has_value());
};
should("produce bail out on map") = [] {
struct {
auto parse(const market_data&) -> std::optional<trade> { return {{}}; }
auto model(const trade&) -> std::optional<order> { return {{}}; }
auto map(const order&) -> std::optional<order_with_id> { return {}; }
} fake_ts;
expect(not execute(fake_ts, {}).has_value());
};
should("produce an order") = [] {
struct {
auto parse(const market_data&) -> std::optional<trade> { return {{}}; }
auto model(const trade&) -> std::optional<order> { return {{}}; }
auto map(const order&) -> std::optional<order_with_id> { return {{}}; }
} fake_ts;
expect(execute(fake_ts, {}).has_value());
};
}
Solutions
std::optional<order_with_id> execute(auto& ts, const market_data& md) {
return ts.parse(md)
.and_then([&](const trade& t) { return ts.model(t); })
.and_then([&](const order& o) { return ts.map(o); });
}
std::optional<order_with_id> execute(auto& ts, const market_data& md) {
auto model = [&ts](const auto &t){ return ts.model(t); };
auto map = [&ts](const auto &o){ return ts.map(o); };
return ts.parse(md)
.and_then(model)
.and_then(map);
}
decltype(auto) operator|(auto&& x, auto&& p) { return x.and_then(p); }
std::optional<order_with_id> execute(auto& ts, const market_data& md) {
return ts.parse(md) | [&ts](auto o) { return ts.model(o); } |
[&ts](auto o) { return ts.map(o); };
}