What is this C++14 construct called which seems to chain lambdas? - c++

This is a follow-up question on this one: Lambda-Over-Lambda in C++14, where the answers explain the code.
It is about a lambda that creates another lambda which when called, calls the passed lambda and passes the return value to the original lambda, thus returning a new instance of the second lambda.
The example shows how this way lambdas can be chained.
Copy from the original question:
#include <cstdio>
auto terminal = [](auto term) // <---------+
{ // |
return [=] (auto func) // | ???
{ // |
return terminal(func(term)); // >---------+
};
};
auto main() -> int
{
auto hello =[](auto s){ fprintf(s,"Hello\n"); return s; };
auto world =[](auto s){ fprintf(s,"World\n"); return s; };
terminal(stdout)
(hello)
(world) ;
return 0;
}
Is there already a name for this construct and if not what should it be called?
Does it resemble constructs in other languages?
Remark: I'm not interested in whether it is actually useful.

I looked around a bit and turns out the main functionality is reordering the function calls as explained in the answers to the original question.
So world(hello(stdout)); is rewritten to terminal(stdout)(hello)(world); which more generally could be written as compose(stdout)(hello)(world);.
In Haskell this would written as world . hello $ stdout and is called function composition.
In clojure it would be (-> stdout hello world) and is called the "thread-first" macro
I think it is only useful with decent partial application which lambdas provide a little bit, so we could have compose(4)([](int x){ return x + 7; })([](int x){ return x * 2; })([](int x){ return x == 22; }); which should return true if my calculation (and blind coding) is any good.
or to emphasize the partial application:
auto add7 = [](int x){ return x + 7; };
auto dbl = [](int x){ return x * 2; };
auto equal22 = [](int x){ return x == 22; };
assert(compose(4)(add7)(dbl)(equals22));
1 major issue with this implementation is probably that the result can't be evaluated because in the end a lambda is returned, so the construction in this answer might be better suited (function separated by comma instead of parenthesis).

terminal(x) returns an applicator that method-chains its return value into terminal for repeated invocation.
But we could instead generalize it.
Suppose you have a function F. F takes an argument, and stuffs it on a stack.
It then examines the stack. If the top of the stack, evaluated on some subset of the stack, would work for invocation, it does it, and pushes the result back onto the stack. In general, such invocation could return a tuple of results.
So:
F(3)(2)(add)(2)(subtract)(7)(3)(multiply)(power)
would evaluate to:
((3+2)-2)^(7*3)
Your terminal does this with 0 argument functions (the first argument) and with 1 argument functions (every argument after that), and only supports 1 return value per invocation.
Doing this with a lambda would be tricky, but what I described is doable in C++.
So one name for it would be stack-based programming.

As far as I know there is no "official" name, yet.
Suggestions:
Lambda chain
Lambda sausage
Curry sausage

Related

Can this be considered a valid C++ variant of a lambda function?

Referencing What is a lambda (function)?
I noticed there was not a C++ solution among the interesting answers.
So I played a little with a C++ solution.
I wonder if this code is a valid C++ version of the adder() function ?
//to accept the 19 i need a rvalue ref.
auto adder = [](int&& x) { auto rv = [&x](int y) {return x + y; };return rv;};
//the similar line to most examples:
auto add5 = adder(19);
std::cout<<"val : "<<add5(4);
Yes thats a completely valid lambda expression.
It's not apparent what is the advantage of nesting is in your example. Though consider a function:
int add(int a, int b) { return a + b; }
When you want to bind a particular value to one of the parameters to get a function you can call with one parameter you can use a lambda expression. And if you want to bind different values you can use a nested lambda expression:
auto add_x = [](int x){ return [x](int y){ return add(x,y); };};
auto add_3 = add_x(3);
auto add_7 = add_x(7);
std::cout << add_3(5); // prints 8
std::cout << add_7(5); // prints 12

Init once with lambda function pointer, self-modifying (C++)

I was wondering if it's possible to create inline lambda initialization function, so after initialization it would replace itself with dummy initialization. Some sort of lazy initialization algorithm with as less pain as possible. Here is some pseudo code what I would like to achieve:
SomeData* data = nullptr;
auto initF = [&]
{
data = initData();
initF = [&] {};
};
so in for loop it would look like this:
for(int i = 0; i < count; i++) {
initF();
data[i] = ....;
}
Basically if count is 0 - initF would not be ever called, but once called - pointer becomes initialized and can be used after that.
Well, your code almost works. Since initF essentially has to change types, from something that actually does work to just a no-op, you can use a std::function:
int data;
std::function<void()> calcData = [&]() {
data = 5; // something expensive
calcData = []() { }
};
I think you can go further and just eliminate data's separate existence, so you just have the function.
std::function<int&()> data = [&]() -> int& {
return (data = [res = 5]() mutable -> int& { return res; })();
// ^^^ the variable becomes a "hidden" data member of the closure
}
This eliminates the chance of accidentally using the variable before you call the initializer.
Use a smart pointer to a closure.
std::shared_ptr<std::function<void(void)>> initf;
Then use std::call_once to initialize it (with some lambda expression), or some static constructor initializing it, e.g.
//untested
initf.reset (& [&] () { initf = [&]() {
auto oldinitf=initf; static int cnt;
cnt++;
std::cout << "cnt=" << cnt << std::endl;
if (oldinitf)
(oldinitf.get()) ();
});
Read also about the Y fix-point combinator in the untyped λ-calculus.
Queinnec's book Lisp in Small Pieces (and Rice's theorem) is related to your question.
Observe that circular references in memory require an indirection at least (so are unfriendly to reference counting approaches).
On Linux you could generate some similar C++ code at runtime (using raw function pointers), compile it into a temporary plugin, and then use dlopen with dlsym (I did that several years ago in GCC MELT, now obsolete). See C++ dlopen minihowto and look into RefPerSys as an example (of a C++ program generating then running C++ code). Look also into JIT compiling libraries such as libgccjit, asmjit, etc...
Observe that such tricks are easier with SBCL, once you made the efforts of learning Common Lisp. SBCL is generating machine code at most REPL interactions.

Why is this recursive lambda function unsafe?

This question comes from Can lambda functions be recursive? . The accepted answer says the recursive lambda function shown below works.
std::function<int (int)> factorial = [&] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
However, it is pointed out by a comment that
such a function cannot be returned safely
, and the reason is supplied in this comment:
returning it destroys the local variable, and the function has a reference to that local variable.
I don't understand the reason. As far as I know, capturing variables is equivalent to retaining them as data members (by-value or by-reference according to the capture list). So what is "local variable" in this context? Also, the code below compiles and works correctly even with -Wall -Wextra -std=c++11 option on g++ 7.4.0.
#include <iostream>
#include <functional>
int main() {
std::function<int (int)> factorial = [&factorial] (int i)
{
return (i == 1) ? 1 : i * factorial(i - 1);
};
std::cout << factorial(5) << "\n";
}
Why is the function unsafe? Is this problem limited to this function, or lambda expression as a whole?
This is because in order to be recursive, it uses type erasure and captures the type erased container by reference.
This has the effect of allowing to use the lambda inside itself, by refering to it indirectly using the std::function.
However, for it to work, it must capture the std::function by reference, and that object has automatic storage duration.
Your lambda contains a reference to a local std::function. Even if you return the std::function by copy, the lambda will still refer to the old one, that died.
To make a secure to return recursive lambda, you can send the lambda to itself in an auto parameter and wrap that in another lambda:
auto factorial = [](auto self, int i) -> int {
return (i == 1) ? 1 : i * self(self, i - 1);
};
return [factorial](int i) { return factorial(factorial, i); };

Is there a name for this tuple-creation idiom?

On the Boost mailinglist, the following clever trick to create a tuple-like entity was recently posted by #LouisDionne:
#include <iostream>
auto list = [](auto ...xs) {
return [=](auto access) { return access(xs...); };
};
auto length = [](auto xs) {
return xs([](auto ...z) { return sizeof...(z); });
};
int main()
{
std::cout << length(list(1, '2', "3")); // 3
}
Live Example.
The cleverness is that list is a lambda taking a variadic parameter-list as input, and returning a lambda as an output that will take another lambda to act on its input. Similarly, length is a lambda taking a list-like entity, to which it will supply the variadic sizeof... operator to the list's original input parameters. The sizeof... operator is wrapped inside a lambda so that it can be passed to the list.
Question: is there a name for this tuple-creation idiom? Perhaps from a functional programming language where higher-order functions are more commonly used.
I think this is a subtle implementation of a Monad-like thing, specifically something in the same spirit of the continuation monad.
Monads are a functional programming construction used to simulate state between different steps of a computation (Remember that a functional language is stateless).
What a monad does is to chain different functions, creating a "computation pipeline" where each step knows about the current state of the computation.
Monads have two primary pilars:
A return function, which takes a value and returns it in a Monad-ready form.
A bind function, which takes a Monad-ready value (From the previous pipeline step) and unwraps it to its original from to pass the value to the next step.
The Wikipedia has very good examples and explanations about monads.
Let me rewrite the given C++14 code:
auto list = []( auto... xs )
{
return [=]( auto access ) { return access(xs...); };
};
I think here we identify the return function of a monad: Takes the value and returns it in a Monadic way.
Specifically, this return returns a functor (In the mathematical sense, not a C++ functor) which goes from the "tuple" category to the variadic pack category.
auto pack_size = [](auto... xs ) { return sizeof...(xs); };
pack_size is just a normal function. It would be used in a pipeline to do some work.
auto bind = []( auto xs , auto op )
{
return xs(op);
};
And length is only a non-generic version of something near to the monad bind operator, an operator which takes a monadic value from a previous pipeline step, and bypasses it to the specified function (Function which really does the work). That function is the functionality done by this computation step.
Finally your call could be rewritten as:
auto result = bind(list(1,'2',"3"), pack_size);
So, whats the name of this tuple creation idiom? Well, I think this could be called "monad-like tuples", since its not exactly a monad, but the tuple representation and expansion works in a similar way, remaining to the Haskell continuation monad.
Edit: More fun
Just for the shake of funny C++ programming, I have followed exploring this monad-like thing. You could find some examples here.
I would call this idiom tuple-continuator or more generally, monadic-continuator. It is most definitely an instance of a continuation monad. A great introduction for continuation monad for C++ programmers is here. In essence, the list lambda above takes a value (a variadic parameter-pack) and returns a simple 'continuator' (the inner closure). This continuator, when given a callable (called access), passes the parameter pack into it and returns whatever that callable returns.
Borrowing from the FPComplete blogpost, a continuator is more or less like the following.
template<class R, class A>
struct Continuator {
virtual ~Continuator() {}
virtual R andThen(function<R(A)> access) = 0;
};
The Continuator above is abstract--does not provide an implementation. So, here is a simple one.
template<class R, class A>
struct SimpleContinuator : Continuator<R, A> {
SimpleContinuator (A x) : _x(x) {}
R andThen(function<R(A)> access) {
return access(_x);
}
A _x;
};
The SimpleContinuator accepts one value of type A and passes it on to access when andThen is called. The list lambda above is essentially the same. It is more general. Instead of a single value, the inner closure captures a parameter-pack and passes it to the access function. Neat!
Hopefully that explains what it means to be a continuator. but what does it mean to be a monad? Here is a good introduction using pictures.
I think the list lambda is also a list monad, which is implemented as a continuation monad. Note that continuation monad is the mother of all monads. I.e., you can implement any monad with a continuation monad. Of course, list monad is not out of reach.
As a parameter-pack is quite naturally a 'list' (often of heterogeneous types), it makes sense for it to work like a list/sequence monad. The list lambda above is a very interesting way of converting C++ parameter-packs to a monadic structure. Therefore, operations can be chained one after another.
The length lambda above, however, is a bit disappointing because it breaks the monad and the nested lambda inside simply returns an integer. There is arguably a better way to write the length 'getter' as shown below.
----Functor----
Before we can say the list lambda is a monad, we have to show that it is a functor. I.e., fmap must be written for list.
The list lambda above serves as the creator of the functor from a parameter pack---essentially it serves as the return. That created functor keeps the parameter-pack with itself (capture) and it allows 'access' to it provided you give a callable that accepts a variable number of arguments. Note that the callable is called EXACTLY-ONCE.
Lets write fmap for such a functor.
auto fmap = [](auto func) {
return [=](auto ...z) { return list(func(z)...); };
};
The type of the func must be (a -> b). I.e., in C++ speak,
template <class a, class b>
b func(a);
The type of fmap is fmap: (a -> b) -> list[a] -> list[b] I.e., in C++ speak,
template <class a, class b, class Func>
list<b> fmap(Func, list<a>);
I.e., fmap simply maps list-of-a to a list-of-b.
Now you can do
auto twice = [](auto i) { return 2*i; };
auto print = [](auto i) { std::cout << i << " "; return i;};
list(1, 2, 3, 4)
(fmap(twice))
(fmap(print)); // prints 2 4 6 8 on clang (g++ in reverse)
Therefore, it is a functor.
----Monad----
Now, lets try to write a flatmap (a.k.a. bind, selectmany)
Type of flatmap is flatmap: (a -> list[b]) -> list[a] -> list[b].
I.e., given a function that maps a to a list-of-b and a list-of-a, flatmap return a list-of-b. Essentially, it takes each element from list-of-a, calls func on it, receives (potentially empty) list-of-b one-by-one, then concatenates all the list-of-b, and finally returns the final list-of-b.
Here's an implementation of flatmap for list.
auto concat = [](auto l1, auto l2) {
auto access1 = [=](auto... p) {
auto access2 = [=](auto... q) {
return list(p..., q...);
};
return l2(access2);
};
return l1(access1);
};
template <class Func>
auto flatten(Func)
{
return list();
}
template <class Func, class A>
auto flatten(Func f, A a)
{
return f(a);
}
template <class Func, class A, class... B>
auto flatten(Func f, A a, B... b)
{
return concat(f(a), flatten(f, b...));
}
auto flatmap = [](auto func) {
return [func](auto... a) { return flatten(func, a...); };
};
Now you can do a lot of powerful things with a list. For example,
auto pair = [](auto i) { return list(-i, i); };
auto count = [](auto... a) { return list(sizeof...(a)); };
list(10, 20, 30)
(flatmap(pair))
(count)
(fmap(print)); // prints 6.
The count function is a monad-perserving operation because it returns a list of single element. If you really want to get the length (not wrapped in a list) you have to terminate the monadic chain and get the value as follows.
auto len = [](auto ...z) { return sizeof...(z); };
std::cout << list(10, 20, 30)
(flatmap(pair))
(len);
If done right, the collection pipeline pattern (e.g., filter, reduce) can now be applied to C++ parameter-packs. Sweet!
----Monad Laws----
Let's make sure the list monad satisfies all three monad laws.
auto to_vector = [](auto... a) { return std::vector<int> { a... }; };
auto M = list(11);
std::cout << "Monad law (left identity)\n";
assert(M(flatmap(pair))(to_vector) == pair(11)(to_vector));
std::cout << "Monad law (right identity)\n";
assert(M(flatmap(list))(to_vector) == M(to_vector));
std::cout << "Monad law (associativity)\n";
assert(M(flatmap(pair))(flatmap(pair))(to_vector) ==
M(flatmap([=](auto x) { return pair(x)(flatmap(pair)); }))(to_vector));
All asserts are satisfied.
----Collection Pipeline----
Although the above 'list' lambda is provably a monad and shares characteristics of the proverbial 'list-monad', it is quite unpleasant. Especially, because the behavior of common collection pipeline combinators, such as filter (a.k.a where) does not meet common expectations.
The reason is just how C++ lambdas work. Each lambda expression produces a function object of a unique type. Therefore, list(1,2,3) produces a type that has nothing to do with list(1) and an empty list, which in this case would be list().
The straight-forward implementation of where fails compilation because in C++ a function can not return two different types.
auto where_broken = [](auto func) {
return flatmap([func](auto i) {
return func(i)? list(i) : list(); // broken :-(
});
};
In the above implementation, func returns a boolean. It's a predicate that says true or false for each element. The ?: operator does not compile.
So, a different trick can be used to allow continuation of the collection pipeline. Instead of actually filtering the elements, they are simply flagged as such---and that's what makes it unpleasant.
auto where_unpleasant = [](auto func) {
return [=](auto... i) {
return list(std::make_pair(func(i), i)...);
};
};
The where_unpleasant gets the job done but unpleasantly...
For example, this is how you can filter negative elements.
auto positive = [](auto i) { return i >= 0; };
auto pair_print = [](auto pair) {
if(pair.first)
std::cout << pair.second << " ";
return pair;
};
list(10, 20)
(flatmap(pair))
(where_unpleasant(positive))
(fmap(pair_print)); // prints 10 and 20 in some order
----Heterogeneous Tuples----
So far the discussion was about homogeneous tuples. Now lets generalize it to true tuples. However, fmap, flatmap, where take only one callback lambda. To provide multiple lambdas each working on one type, we can overload them. For example,
template <class A, class... B>
struct overload : overload<A>, overload<B...> {
overload(A a, B... b)
: overload<A>(a), overload<B...>(b...)
{}
using overload<A>::operator ();
using overload<B...>::operator ();
};
template <class A>
struct overload<A> : A{
overload(A a)
: A(a) {}
using A::operator();
};
template <class... F>
auto make_overload(F... f) {
return overload<F...>(f...);
}
auto test =
make_overload([](int i) { std::cout << "int = " << i << std::endl; },
[](double d) { std::cout << "double = " << d << std::endl; });
test(10); // int
test(9.99); // double
Let's use the overloaded lambda technique to process a heterogeneous tuple continuator.
auto int_or_string =
make_overload([](int i) { return 5*i; },
[](std::string s) { return s+s; });
list(10, "20")
(fmap(int_or_string))
(fmap(print)); // prints 2020 and 50 in some order
Finally, Live Example
This looks like a form of continuation passing style.
The rough idea of CPS is this: instead of having a function (say f) return some value, you give to f another argument, which is a function, called a continuation. Then, f calls this continuation with the return value instead of returning. Let's take an example:
int f (int x) { return x + 42; }
becomes
void f (int x, auto cont) { cont (x + 42); }
The call is a tail call, and can be optimized into a jump (this is why TCO is mandated in some languages, like Scheme, whose semantics rely on some form of transformation into CPS).
Another example:
void get_int (auto cont) { cont (10); }
void print_int (int x) { printf ("%d", x), }
You can now do get_int (std::bind (f, _1, print_int)) to print 54. Note that all the continuation calls are always tail calls (the call to printf is also a continuation call).
A well-known example is asynchronous callbacks (AJAX calls in javascript for instance): you pass a continuation to a routine executing in parallel.
Continuations can be composed (and form a monad, in case you're interested), as in the above example. In fact it is possible to transform a (functional) program entirely into CPS, so that every call is a tail call (and then you need no stack to run the program !).

What is wrong with my Phoenix lambda expression?

I would expect the following example Boost Phoenix expression to compile.
What am I missing?
int plus(int a,int b)
{
return a+b;
}
void main(int argc,char** argc)
{
auto plus_1 = phx::bind(&plus,1,arg1);
auto value = phx::lambda[phx::val(plus_1)(arg1)]()(1);
std::cout << value << std::endl;
}
auto plus_1 = phx::bind(&plus,1,arg1);
After this line, plus_1 is a function object that takes one int argument and adds one to it.
phx::lambda[plus_1(arg1)](1);
Whoops. This isn't going to work because (as we said above) plus_1 is a function object that takes one int argument and adds one to it. Here, you're trying to invoke it with arg1.
It isn't obvious from your code what you expect it to do. Can you clarify?
====EDIT====
I see you've edited the code in your question. Your code is still wrong but for a different reason now. This:
phx::val(plus_1)(arg1)
... uses val to create a nullary function that returns the plus_1 unary function. You then try to invoke the nullary function with arg1. Boom.
Here is code that executes and does (what I believe) you intend:
#include <iostream>
#include <boost/phoenix/phoenix.hpp>
namespace phx = boost::phoenix;
using phx::arg_names::arg1;
int plus(int a,int b)
{
return a+b;
}
int main()
{
auto plus_1 = phx::bind(&plus, 1, arg1);
int value = phx::bind(phx::lambda[plus_1], arg1)(1);
std::cout << value << std::endl;
}
The first bind takes the binary plus and turns it into a unary function with the first argument bound to 1. The second bind creates a new unary function that is equivalent to the first, but it does so by safely wrapping the first function using lambda. Why is that necessary? Consider the code below, which is equivalent, but without the lambda:
// Oops, wrong:
int value = phx::bind(phx::bind(&plus, 1, arg1), arg1)(1);
Notice that arg1 appears twice. All expressions get evaluated from the inside out. First, we'll bind the inner arg1 to 1, then evaluate the inner bind yielding 2, which we then try to bind and invoke. That's not going to work because 2 isn't callable.
The use of lambda creates a scope for the inner arg1 so it isn't eagerly substituted. But like I said, the use of the second bind, which forces the need for lambda, yields a function that is equivalent to the first. So it's needlessly complicated. But maybe it helped you understand about bind, lambda and Phoenix scopes.
It's not clear to me what you're trying to accomplish by using lambda here, but if you just want to call plus_1 with 1 (resulting in 2), it's much simpler than your attempt:
#include <iostream>
#include <boost/phoenix.hpp>
int plus(int a, int b)
{
return a + b;
}
int main()
{
namespace phx = boost::phoenix;
auto plus_1 = phx::bind(plus, 1, phx::arg_names::arg1);
std::cout << plus_1(1) << '\n';
}
Online demo
If this isn't what you're trying to accomplish, then you need to describe what you actually want. :-]
Perhaps this can explain it better.
Phoenix is not magic; it is first and foremost C++. It therefore follows the rules of C++.
phx::bind is a function that returns a function object, an object which has an overloaded operator() that calls the function that was bound. Your first statement stores this object into plus_1.
Given all of this, anytime you have the expression plus_1(...), this is a function call. That's what it is; you are saying that you want to call the overloaded operator() function on the type of that object, and that you are going to pass some values to that function.
It doesn't matter whether that expression is in the middle of a [] or not. phx::lambda cannot make C++ change its rules. It can't make plus_1(...) anything other than an immediate function call. Nor can arg1 make plus_1(...) not an immediate function call.