C++ is surprisingly close to being a usable functional language.
The two missing pieces are -
* structural pattern matching
* uniform function call syntax that is : a.foo(b) vs foo(a, b) being interchangeable.
With the kitchen sink approach of design I’d not be surprised if these get into the language eventually. These ideas have been proposed a few times but haven’t been seriously considered as far as I know.
* Some standards such as ISO 6709 (Standard representation of geographic point location by coordinates) describe points as (latitude, longitude).
* Others such as RFC 7946 (GeoJSON) describes points as (longitude, latitude).
Using (hypothetical) std::flip to reify these APIs seems like a loaded footgun - someone is bound to accidentally use it {zero, two} times to convert between orders when it needs to be used once and wreak havoc.
I love Haskell but when writing C++ I always avoid functional style gibberish. I feel like this style of programming only works in languages properly designed for that.
When C++23 is fully supported functional style will be somewhat bearable, but even then a lot is missing. Lambdas are just too verbose to make this fun.
> Interestingly enough, most of these implementations only flip the first two parameters of whichever function they are passed, though it seems to be because most of them are based on the Haskell prelude, and handling arbitrary arity can be tricky in that language.
Probably because the use case for it with higher arity is hard to imagine. (Indeed, TFA gives only examples with binary operations.)
> Fortunately it is not just useless knowledge either: flip can be reified at will by copying the following C++17 implementation.
(I leave keyword arguments alone because there's no clearer semantic for "flipping" them.)
The `toolz.functoolz.flip` implementation (being restricted to binary functions) is an even simpler one-liner (https://toolz.readthedocs.io/en/latest/_modules/toolz/functo...), though accompanied by a massive docstring and admittedly simplified through a heavyweight currying decorator (which accomplishes much more than simply getting a function that does the right thing).
The best I could get the fully general version is still pretty obtuse though:
// std doesn't have a template version of placeholders::_1, _2, etc., so we need to
// define our own.
template <int I> struct placeholder{};
template<>
template<int I>
struct std::is_placeholder<placeholder<I>> : std::integral_constant<int, I> {};
// flip must be an object so that the function type can be deduced without needing
// to explicitly specify its parameters' types.
template<typename F>
struct flip {
const F f;
// operator() deduces the argument types when the flip object is called, but really
// all we need to know is the number of arguments.
template<typename... Args>
constexpr auto operator()(Args... args) {
return bind_reversed(std::make_integer_sequence<int, sizeof...(Args)>{})(args...);
}
private:
// a helper function is needed to deduce a sequence of integers so we can bind all
// the placeholder values.
template<int... Is>
constexpr auto bind_reversed(std::integer_sequence<int, Is...>) {
return std::bind(f, placeholder<sizeof...(Is) - Is>{}...);
}
};
Very soon after reading this I started to doubt my whole life's work in C++... std::flip? Never heard of it before, and I used to read cppreference for fun. And the name smells sus. I don't think the committee would name it "flip" if it did exist. Too short a name for something too niche. I looked at cppreference and saw that yep, this does not exist, so thought maybe this article was some kind of AI hallucination. Finally the author said it was all made up and my mind was at peace once more.
Funny enough, I've known it exists. I've never really found much of a use case for it. Where I have found it "might" be useful is rare one-off APIs. If I were to write a wrapper for one API to work with an equivalent API, then maybe I might use this. But for one-off things, it's not important enough to use IMO.
On the other hand, I remember reading it and thing it was a bit-flip operation since it's in <functional> instead of <tuple>. So I was quite surprised to find that it's really much more like a tuple operation (which is template magic) than bit flipping (at runtime, or possibly also constexpr)
> `std::flip` finds its roots in functional programming, a domain in which it is extremely prevalent:
This is enough to determine it is written by Chatgpt.
If you're not familiar with Chatgpt, ChatGPT finds its roots in advanced machine learning research, particularly in the field of natural language processing (NLP), where it leverages deep learning models like GPT (Generative Pretrained Transformer) to understand, generate, and interact with human language based on vast amounts of data and context.
This seems like an obvious functional-style function that C++ should have, given the trend for functional idioms in recent versions. However, even a C++ cynic such as myself was shocked by the length and (to me) incomprehensible implementation at the end of the article. A definition of that complexity for something so simple tells me that something has gone off the rails. The equivalent function in Haskell, fwiw, can be implemented in its entirety as follows:
flip :: (a -> b -> c) -> b -> a -> c
flip f x y = f y x
flip is called flipargs because flip is the name of an operator that mutates a place with a negation of its current value: i.e (flip x) means (set x (not x)) with x evaluated once.
18 comments
[ 2.6 ms ] story [ 35.8 ms ] threadThe two missing pieces are -
* structural pattern matching
* uniform function call syntax that is : a.foo(b) vs foo(a, b) being interchangeable.
With the kitchen sink approach of design I’d not be surprised if these get into the language eventually. These ideas have been proposed a few times but haven’t been seriously considered as far as I know.
Probably because the use case for it with higher arity is hard to imagine. (Indeed, TFA gives only examples with binary operations.)
> Fortunately it is not just useless knowledge either: flip can be reified at will by copying the following C++17 implementation.
> [snip 114 lines of code]
Meanwhile, in Python:
(I leave keyword arguments alone because there's no clearer semantic for "flipping" them.)The `toolz.functoolz.flip` implementation (being restricted to binary functions) is an even simpler one-liner (https://toolz.readthedocs.io/en/latest/_modules/toolz/functo...), though accompanied by a massive docstring and admittedly simplified through a heavyweight currying decorator (which accomplishes much more than simply getting a function that does the right thing).
I hope not.
Yeah, this would be std::reverse_bind() or something.
On the other hand, I remember reading it and thing it was a bit-flip operation since it's in <functional> instead of <tuple>. So I was quite surprised to find that it's really much more like a tuple operation (which is template magic) than bit flipping (at runtime, or possibly also constexpr)
This is enough to determine it is written by Chatgpt.
If you're not familiar with Chatgpt, ChatGPT finds its roots in advanced machine learning research, particularly in the field of natural language processing (NLP), where it leverages deep learning models like GPT (Generative Pretrained Transformer) to understand, generate, and interact with human language based on vast amounts of data and context.
The Lisp family doesn't provide anything but parentheses, maybe lambda (not necessarily under that name) and a whole lot of heated arguments.
Only specific dialects of specific Lisp-family languages provide, or don't provide this and that:
TXR Lisp:
flip is called flipargs because flip is the name of an operator that mutates a place with a negation of its current value: i.e (flip x) means (set x (not x)) with x evaluated once.