std::transform
from the <algorithm>
header applies to ranges, and it is what "enables" us to use ranges as the functors they are (in the sense of category theory(¹)). std::transform
is iterator-based, yes, but std::ranges::views::transform
is not, and its signature closely matches the signature of corresponding functions in functional languages (modulo the different order of the two arguments, but this is not a big deal).
When I saw this question (and in the process of answering to it), I learned that C++23 introduces std::optional<T>::transform
, which makes std::optional
a functor too.
All these news truly excite me, but I can't help thinking that functors are general, and that it'd be nice to have a uniform interface to transform
any functor, as is the case in Haskell, for instance.
This makes me think that an object similar to std::ranges::views::transform
(with a different name not alluding to ranges
) could be made a customization point that the STL would customize not just for ranges, but also for std::optional
and for any other functor in the STL, whereas the programmer could customize it for their user-defined classes.
Quite similarly, C++23 also introduces std::optional<T>::and_then
, which is basically the monadic binding for std::optional
. I'm not aware of any similar function that implements monadic binding for ranges, but C++20's some_range | std::ranges::views::transform(f) | std::ranges::views::join
is essentially the monadic binding of some_range
with f
.
And this makes me think that there could be some generic interface, name it mbind
, that one can opt in with any type. The STL would opt in for std::optional
by implementing it in terms of std::optional<T>::and_then
, for instance.
Is there any chance, or are there any plans that the language will one day support such a genericity?
I can certainly see some problems. Today No quite, breaking code that relies on SFINAE-based detection of invalid code is ok.std::ranges::views::transform(some_optional, some_func)
is invalid, so some code might be relying on that via SFINAE. Making it suddenly work would break the code.
(¹) As regards the word functor, I refer to the definition that is given in category theory (see also this), not to the concept of "object of a class which has operator()
defined"; the latter is not defined anywhere in the standard and is not even mentioned on cppreference, which instead uses the term FunctionObject to refer to
an object that can be used on the left of the function call operator
optional
operations in. I don't personally see the committee embracing category theory for the future even if there are certainly people on it who are familiar with Haskell or similar. – Corm