Understanding Y Combinator through generic lambdas - c++

While building a small lambda-based metaprogramming library, I had the necessity of using recursion in a C++14 generic lambda, to implement a left-fold.
My own solution was passing the lambda itself as one of its parameters, like this:
template <typename TAcc, typename TF, typename... Ts>
constexpr auto fold_l_impl(TAcc acc, TF f, Ts... xs)
{
// Folding step.
auto step([=](auto self)
{
return [=](auto y_acc, auto y_x, auto... y_xs)
{
// Compute next folding step.
auto next(f(y_acc, y_x));
// Recurse if required.
return static_if(not_empty(y_xs...))
.then([=]
{
// Recursive case.
return self(self)(next, y_xs...);
})
.else_([=]
{
// Base case.
return next;
})();
};
});
// Start the left-fold.
return step(step)(acc, xs...);
}
step is the "main" lambda that starts off the recursion. It returns a function with the desired left-fold signature (accumulator, current item, remaining items...).
The function calls itself recursively by using self(self)(next, y_xs...).
I've recently come across this proposal that wants to add a Y Combinator to the Standard Library, and after reading it, it seems extremely similar to what I am doing here.
Unfortunately, the concept of the Y Combinator still doesn't "click" for me - I am missing something and I cannot visualize how to generalize what I did with the self parameter for any function, avoiding the step boilerplate.
I've read this excellent StackOverflow answer regarding the matter, but it still didn't "click" for me.
(From that answer) a recursive factorial is defined this way:
fact =
(recurs) =>
(x) =>
x == 0 ? 1 : x * recurs(x - 1);
The recurs parameter seems to have the same role as my self parameter. What I do not understand is how recurs is called without passing recurs into itself again.
I have to call self like this: self(self)(params...).
recurs, however, is called like recurs(params...).
Attempting to call self(params...) results in a compiler error informing me that self requires only a single parameter (which is the auto self lambda parameter).
What am I missing here? How could I rewrite my fold_l_impl lambda in such a way that its recursion could be generalized through the use of a Y Combinator?

Here is a y combinate where the lambda is passed a recurs that doesn't need to be passed recurs:
template<class F>
struct y_combinate_t {
F f;
template<class...Args>
decltype(auto) operator()(Args&&...args)const {
return f(*this, std::forward<Args>(args)...);
}
};
template<class F>
y_combinate_t<std::decay_t<F>> y_combinate( F&& f ) {
return {std::forward<F>(f)};
};
then you do:
return y_combinate(step)(acc, xs...);
and change
return self(self)(next, y_xs...);
to
return self(next, y_xs...);
the trick here is I used a non-lambda function object that has access to its own this, which I pass to f as its first parameter.

Related

How to rewrite template function to allow code reuse

Consider the following template recursion function. Its purpose is to create a vector containing all values in the enum class EnumClassName for which its associated predicate function bool xxx<N>() returns true.
template <EnumClassName N = EnumClassName::LAST_ENUM_VALUE>
std::vector<EnumClassName> xxx_stuff()
{
std::vector<EnumClassName> v = xxx_stuff<EnumClassName(static_cast<int>(N) - 1)>();
if (xxx<N>()) {
v.emplace_back(N);
}
return v;
}
with the recursion base case:
template <> std::vector<EnumClassName> xxx_stuff<EnumClassName::FIRST_ENUM_VALUE>()
{
return {};
}
Now assume there are 10 of these functions where the only thing that differs is the xxx name. I.e. we have the functions alpha_stuff with a corresponding predicate function alpha<N>, beta_stuff with a corresponding predicate function beta<N>, etc etc.
Is there any way to not duplicate the above function 10 times, where the only difference is the replacement of xxx with alpha, beta etc in each duplicate?
I am not able to just loop over the enum values, because the xxx<N> functions in turn call another function yyy<N> which will not accept a runtime-generated template argument <N> (forgive my lingo there, I actually have no idea what I'm talking about or how this works, I just know it gave me compilation errors when I tried it that way).
You cannot pass function template as argument or overloaded function, but you can wrap the call in a type, and then
template <typename EnumClassName,
EnumClassName N = EnumClassName::LAST_ENUM_VALUE,
typename F>
std::vector<EnumClassName> xxx_stuff(F&& f)
{
std::vector<EnumClassName> v =
xxx_stuff<EnumClassName, EnumClassName(static_cast<int>(N) - 1)>(f);
if (f(std::integral_constant<EnumClassName, N>{})) {
v.emplace_back(N);
}
return v;
}
with usage
auto v = xxx_stuff<E>([](auto n) { return xxx<n()>(); });
Demo
Note: That recursion can be avoided using std::integer_sequence.

Template substitution failure with empty parameter pack using a Y-combinator

I am trying to make a function that will read from a pipe to a buffer using boost::asio::posix::stream_descriptor. I use async_read_some rather than boost::asio::async_read because it is important for me to be immediately notified as soon as a chunk of data is read. What I want to do after reading data from the pipe is
Move the writer pointer of my buffer
Do something with the newly got data
Schedule the read of more data
I wanted to duplicate as little code as possible, so I ended up with a functional programming mess that I would be very curious to know why it does not work.
asio::posix::stream_descriptor inputPipe{context, input.fd};
char buffer[2048]; // simple buffer for demonstration purposes
char* end = buffer + 2048;
char* writer = buffer;
// the interesting part
yCombinator([&](auto&& self_) {
inputPipe.async_read_some(asio::buffer(writer, end - writer), [&](boost::system::error_code errorCode_, size_t transferedCount_) -> void {
writer += transferedCount_;
// ... be something, go somewhere, do something, make things change ...
self_(self_); // self_ contains the async_read_some, so it schedules the next read
});
})();
Where I proudly present yCombinator as:
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr noexcept(std::is_nothrow_invocable_v<Fn, decltype(args_)...>)->std::invoke_result_t<Fn, decltype(args_)...> {
return std::invoke(std::get<0>(capture), std::get<0>(capture), std::forward<decltype(args_)>(args_)...);
};
}
Currently the aforementioned code fails to compile. G++ complains that candidate template ignored: substitution failure [with args_:auto = <>]: no type named 'type' in 'std::invoke_result<(lambda at redacted.cpp:80:21)>'. I understand this has to have something to do with the trailing return type of the lambda being returned from yCombinator. I suppose that the issue could be that args_ is an empty parameter pack, but I am not really sure how to deal with that. But at the same time, if this is the issue, than why does everything seem okay with the std::is_nothrow_invocable_v trait?
You have several issues:
First, there is a mismatch between return type/noexcept and function body:
miss Fn in the formers
template<typename Fn>
constexpr auto yCombinator(Fn&& fn_) noexcept {
return [capture = std::tuple{std::forward<Fn>(fn_)}](auto&&... args_) constexpr
noexcept(std::is_nothrow_invocable_v<Fn, Fn, decltype(args_)...>)
// ^^
-> std::invoke_result_t<Fn, Fn, decltype(args_)...>
// ^^
{
return std::invoke(std::get<0>(capture),
std::get<0>(capture),
std::forward<decltype(args_)>(args_)...);
};
}
Then, to deduce non-provided return type, we have to "look" in the body, and so use self_ return type before we deduce it.
Solution is to provide type explicitly:
yCombinator([&](auto&& self_) -> void
// ^^^^^^^
{
// ...
self_(self_);
})();

Some explaination about C++ code (lambda wrapper and variadic template)

Can someone explain to me what does this piece of code step by step? I found it in this topic : Segmentation fault on gcc caused by lambda wrapper over variadic template function call and I don't understand nothing :
template <typename TNode, typename... TNodes>
auto execute(TNode& n, TNodes&... ns)
{
[&](){ n.execute(ns...); }();
}
Especially the part : [&](){ n.execute(ns...); }();
Is there any connection with lambda calculus and programmation language like caml or ocaml?
Thank you in advance
This part [&](){ n.execute(ns...); }(); creates a new lambda and execute it directly. It is equal to:
auto temp= [&](){ n.execute(ns...); };
temp();
This part n.execute(ns...); is calling a member function called TNode::execute which accepts many parameters (variadic template argument) of the types TNodes...

std::async vs std::promise

I have to wrap a getter function into a std::future object.
std::function<String (String)> -> std::function<std::future<String> (String)>
So simple question, what is the best / fastest way to do this?
Here are two options I came up with.
I have a function:
std::function<String (String)> getter;
Then wrap this using std::promise:
std::function<std::future<String> (String)> binding = [getter](String context) {
std::promise<String> p;
p.set_value(getter(contex));
return p.get_future();
};
Or using std::async:
std::function<std::future<String> (String)> binding = [getter](String context) {
return std::async(std::launch::deferred, getter, contex);
};
The right answer is to write your own make_ready_future (right out of std::experimantal). std::promise is about the only way I know of to produce a ready future: async produces non-ready futures.
This takes a value, and produces a future of that value, with some fancy stuff involving reference wrappers (which you can optionally skip).
A proposal to add it in C++1z exists, so by basing your own version off its interface, you can semi future-proof your code. Plus, as an audited design, it will suck less than your own.
Once you have it written:
template<class F>
auto futuristic_wrapper( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args){
return make_ready_future( f( decltype(args)(args)... ) );
};
}
in C++11 you'd have to write a class to replace the lambda:
template<class F>
struct futurize {
F f;
template<class...Args>
operator()(Args&&...args)const->
delctype(make_ready_future(f(std::forward<Args>(args)...)))
{ return make_ready_future(f(std::forward<Args>(args)...)); }
};
template<class F>
auto futuristic_wrapper( F&& f )->
futurize< typename std::decay_t<F>::type >
{
return {std::forward<F>(f)};
}
which is annoying, but mostly a mechanical transformation.
This doesn't actually produce a std::function< future<R>(Args...) >, but it will return something convertible to that. No need to type erase if we don't need to after all.
You can put "your own version of to-be-standardized stuff" you steal from std::experimantal in a namespace like notstd. Always use it with notstd:: (never using namespace notstd;, and not using notstd::make_ready_future; as that risk behavior changes when the type is added to std) to be clear to later users that this is NOT the standard version of these objects.

C++ alternative to params object[] in C#

Hello Guys so i want to code something in C++ that i have for C# but as there is no params object in C++ i need some help :P
Ok, so here's what i want to do:
static Int32 Procedure(UInt32 address, params Object[] parameters)
{
Int32 length = parameters.Length;
Int32 index = 0;
UInt32 count = 0;
UInt32 Strings = 0;
UInt32 Single = 0;
UInt32 Array = 0;
while (index < length)
{
if (parameters[index] is Int32)
{
WriteInt32(0x10050000 + (count * 4), (Int32)parameters[index]);
count++;
}
else if(paramaters[index] is String){ }.... // Thats just one thing i wanna use.. i've got more
..........
..........
}
return ReadInt32(0x000000);
}
so i need to figure out what type the parameter is + i wanna use an unknown amount of arguments and i have no idea how i would do this xD
I hope its clear and hopefully someone can Help me :3
Thx, Nico!
You can achieve something similar in C++ with variadic templates. Note that since C++ has no runtime reflection, it's not possible to dynamically get the type of any value: it can only be done at compile-time. Importantly, this also means that you cannot build a parameter list at runtime and pass it to the function without rolling out your own stuff to do it.
It is also arguably much more complicated than a C# equivalent (but then again, if C++ had all the strengths of C# with no weaknesses of itself, nobody would be using C#).
There may be other patterns, but the one I usually use looks like this (example with a print function):
template<typename... T>
void print_all_values(int value, T... values)
{
printf("%i ", value);
print_all_values(values...);
}
template<typename... T>
void print_all_values(double value, T... values)
{
printf("%g ", value);
print_all_values(values...);
}
template<typename... T>
void print_all_values(const char* value, T... values)
{
printf("%s ", value);
print_all_values(values...);
}
template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)
{
printf("(can't print) ");
print_all_values(values...);
}
void print_all_values() {}
print_all_values(4, "hello world", 5.2, nullptr);
// prints: "4 hello world 5.2 (can't print)"
What happens here:
template<typename... T>
void print_all_values
This tells the compiler to create a distinct version of print_all_values for each different parameter type sequences it finds in my program.
void print_all_values(int value, T... values)
void print_all_values(double value, T... values)
void print_all_values(const char* value, T... values)
These differentiate the call per the first parameter. The idea here is that the function will only print its first parameter, then recursively call the template version with the remaining parameters:
{
printf("%s ", value);
print_all_values(values...);
}
At the end of the recursion chain, each parameter has been printed.
For my example print_all_values(4, "hello world", 5.2, nullptr), this is basically what would happen:
print_all_values(4, "hello world", 5.2, nullptr) -> the compiler uses print_all_values(4, ...), at runtime it'll do printf("%i", value), and the call at the end of the function becomes:
print_all_values("hello world", 5.2, nullptr) -> the compiler uses print_all_values("hello world", ...), at runtime it'll do printf("%s", value), and then:
print_all_values(5.2, nullptr) -> the compiler uses print_all_values(5.2, ...), printf("%g", value), then:
print_all_values(5.2, nullptr) -> the compiler can't find a suitable overload, so it falls back to the print_all_values(Unknown&& value, T... values) overload, does "(can't print)", and creates a call to print_all_values(), which does nothing.
The last overload:
template<typename Unknown, typename... T>
void print_all_values(Unknown&& value, T... values)
tells the compiler how handle any unknown type (in this case by printing (can't print)). Without this overload, we'd get a compile-time error if we tried to print an unknown type (because it all happens at compile-time, remember).
Did you already try a variadic template declaration like given in the following sample?
template<typename... Args>
static int32_t Procedure(uint32_t address, Args&&... parameters) {
// ...
}
C++ allows you to write functions accepting any number of parameters in the form of variadic template functions:
template<typename... ARGS>
void f( ARGS... args )
{
}
In that example, ARGS and args denote what is known as variadic packs. Neither are a template parameter or an function parameter, are just something that represents a set of template parameters, and a set of function parameters (Respectively).
So that are not parameters, are parameter packs, and then them cannot be manipulated directly. To use the content of a variadic pack, you have to expand the pack with an ellipsis.
Consider the example above: template<typename... ARGS> declares a variadic template with a variadic-pack named ARGS which represents a set of type template parameters.
In the next line, we expand that pack (ARGS...) to use that types as the types of the function argumments. That generates the variadic pack of function argumments args.
To use that argumments inside the function, you should expand args too. Since a pack is just a indetermined set of argumments, you can only use it in contexts where you use the hole set of argumments, in other words, you cannot access directly an specific element of the pack. For example:
template<typename... ARGS>
void f( ARGS... args )
{
f( args... ); //We call f() expanding the args pack of function parameters
//and passing the set of parameters to the function.
}
If you need to traverse the set of parameters in a pack (Which you would do in C# using the subscript operator on the params), you have to use the functional programming way of pattern matching and head-tail recursive list traversing:
template<typename HEAD , typename... TAIL>
void print( const HEAD& head , const TAIL&... tail )
{
std::cout << head << std::endl; //Do something with the head (Which is a
//normal function parameter)
print( tail... ); //Pass the tail to the next call
}
Note that function expects at least one parameter (A variadic template could be empty, but print() has one non-variadic parameter) . You should provide an overload with no parameters to act as base case (The case when there is no more argumments in the argumments list):
void print()
{
//Base case. Does nothing.
}
Now consider the signature of the print() function: Is a function which can take any number of parameters of any combination of types. In contrast to the C# (And Java) approach, storing the parameters in an array of an universal base class, and rely on polymorphism and casting), the C++ approach uses a statically-typed alternative, where the type of each function parameter is well determined at compile time.