C 23 adds some "monadic-style" functionality regarding optionals, as methods of optional<T>
:
optional<T>::and_then()
(and ignoring qualifiers of this
):
template<class F> constexpr auto and_then(F&& f);
Returns the result of invocation of f on the contained value if it exists. Otherwise, returns an empty value of the return type.
optional<T>::transform()
(and ignoring qualifiers of this
):
template<class F> constexpr auto transform(F&& f);
Returns an
std::optional
that contains the result of invocation off
on the contained value if*this
contains a value. Otherwise, returns an emptystd::optional
of such type.
So, aren't these two functions doing the same thing?
CodePudding user response:
The phrasing, and the unqualified template, aren't super-helpful in figuring out the difference, but: transform()
does "re-boxing" into an optional, but and_then()
does not, expecting the function to returned a boxed value on its own. So,
transform()
is for when you want to use a function likeT2 foo(T1 x)
.and_then()
is for when you want to use a function likeoptional<T2> bar(T1 x)
.
Both my_optional.transform(foo)
and my_optional.and_then(bar)
return a value of type optional<T2>
.
See also this question.
CodePudding user response:
and_then
is monadic bind
aka flatmap
aka >>=
and transform
is functorial map
.
One can express map
in terms of bind
generically, but not the other way around, because a functor is not necessarily a monad. Of course the particular monad of std::optional
can be opened at any time, so both functions are expressible in terms of ordinary pre-C 23 std::optional
API. Thus the question why the C standard defines both functions is no better than the question why it defines any of the two. Perhaps the Standard wishes to give the programmer a standard functorial interface and a standard monadic interface independently. Either interface is useful and important on its own right.