4

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 different order of the two arguments.

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 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

Enlico
  • 17,834
  • 5
  • 39
  • 78
  • "*which makes std::optional a functor too.*" How does this make `optional` a functor? – 康桓瑋 Jan 09 '22 at 11:12
  • A datatype representing an optional value _is_ a functor. Haskell names it `Maybe`, C++ names it `std::optional`. Haskell encodes the fact that it is a functor by implementing `fmap` for `Maybe`s. In C++ there's this `std::optional::transform` that serves the same purpose, the only difference with respect to Haskell's `fmap` being that it is a memebr function. – Enlico Jan 09 '22 at 11:20
  • Is there some technical reason that makes you think adopting these changes would be impossible/hard? – idmean Jan 09 '22 at 11:38
  • @康桓瑋 does _in the categorical sense_ solve the ambiguity? – Enlico Jan 09 '22 at 11:59
  • @idmean, I've mentioned one possible problem. SFINAE code relying on the non validity of some code would break. – Enlico Jan 09 '22 at 13:32
  • I can only speculate, but I find it very unlikely. It was painful enough getting those `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. – chris Jan 10 '22 at 03:08

0 Answers0