Skip to content

Monadic Operations for etl::expected #1207

@whitfijs-jw

Description

@whitfijs-jw

I have been playing around with adding monadic operations (and_then, or_else, transform, transform_error) to etl::expected. I couldn't find any mention of adding them to the project, so I apologize if this has already been discussed.

A first draft of the implementation is here in expected.h, there are still some static_asserts and stl calls that would need to be swapped out for their etl equivalents. I also added simple, non-exhaustive unit tests, but I haven't run them against the full suite of compilers and c++ standard.

An example of transform and some helper traits:

  template <typename F, typename T>
  struct deduced_result_type {
    using type = std::decay_t<decltype(std::declval<F>()(std::declval<T&&>()))>;
  };

  template <typename F, typename T>
  using deduced_result_type_t = typename deduced_result_type<F, T>::type;

  template <typename F>
  auto transform(F&& f) const & {
    using U = typename deduced_result_type<F, TValue>::type;
    using new_expected = expected<U,TError>;

    if (has_value()) {
        return new_expected(f(etl::get<TValue>(storage)));
    } else {
        return new_expected(
          unexpected<TError>(etl::get<TError>(storage))
        );
    }
  }

  template <typename F>
  auto transform(F&& f) && {
    using U = typename deduced_result_type<F, TValue>::type;
    using new_expected = expected<U,TError>;

    if (has_value()) {
        return new_expected(f(etl::get<TValue>(etl::move(storage))));
    } else {
        return new_expected(
          unexpected<TError>(etl::get<TError>(etl::move(storage)))
        );
    }
  }

and an example usage in a simple unit test:

    TEST(test_transform_with_value) {
      struct Transform{
        Expected produceValue() {
          return Value("produceValue()");
        }
      };

      Transform transform;
      auto expected = transform.produceValue().transform([](Value v) {
        CHECK_EQUAL("produceValue()", v.v);
        auto s = v.v.append(" transformed");
        return s;
      });
      CHECK_TRUE(expected.has_value());
      CHECK_TRUE(bool(expected));
      CHECK_EQUAL("produceValue() transformed", expected.value());
    }

This is far from polished, but I didn't want to spend too much more time on it if there's no interest in adding it to the project.

Metadata

Metadata

Assignees

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions