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 !).
Related
I know that it is possible to get a random tuple element at runtime. Behind the scenes, make_integer_sequence and integer_sequence can get all elements at compile time and offer access to these elements at runtime.
But my problem is that it seems only to be possible to access the elements of a random index only with a lambda or function pointer. I would like to get the lambda to return the element-reference so that I could get something like this:
auto myElement = runtime_get(mytuple, 5);
I don't know how I could do this. Working with templates isn't that new to me but templates can get very difficult to understand if they become complex. I'm trying to learn more about them by playing a little bit with the tuple-stuff.
I think, this should work: runtime_get<std::string>(0, mytuple), so the type is predetermined.
Yes, this is certainly possible, but you need to do something if the runtime index isn't the right type. For example, throw an exception.
Here's one sample implementation, but note that I condensed it at the expense of some readability. Member function pointers and templated lambdas is possibly the worst combination of features the language has to offer, but it was pretty concise (live example):
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
using Tuple = std::tuple<Ts...>;
// A set of functions to get the element at one specific index
auto get_at_index = []<std::size_t I>(Tuple& tuple) -> Result& {
if constexpr (std::is_same_v<std::tuple_element_t<I, Tuple>, Result>) {
return std::get<I>(tuple);
} else {
throw std::runtime_error("Index does not contain the right type");
}
};
// Regular index_sequence trick to get a pack of indices
return [&]<std::size_t... Is>(std::index_sequence<Is...>) -> Result& {
// The type of a single member function pointer of the closure type, using awkward memfun syntax
using FPtr = auto(decltype(get_at_index)::*)(Tuple&) const -> Result&;
// An array of said memfun pointers, each for one known index
FPtr fptrs[sizeof...(Ts)]{&decltype(get_at_index)::template operator()<Is>...};
// Invoke the correct pointer
return (get_at_index.*(fptrs[i]))(t);
}(std::index_sequence_for<Ts...>());
}
int main() {
std::tuple<std::string, int, double, std::string> t{"abc", 2, 5.9, "def"};
for (int i = 0; i < 4; ++i) {
try {
std::string& s = runtime_get<std::string>(i, t);
std::cout << "Success: " << s << '\n';
} catch (const std::runtime_error& ex) {
std::cout << "Failure: " << ex.what() << '\n';
}
}
}
Success: abc
Failure: Index does not contain the right type
Failure: Index does not contain the right type
Success: def
This is just the lvalue reference version, you might need other overloads. If you want a more reusable bit of trickery for the runtime-to-compile-time index conversion that you can hide away in a header, check out the std::call proposal.
Note also that this can be built out of a callback-based solution:
template<typename Result, typename... Ts>
auto runtime_get(std::size_t i, std::tuple<Ts...>& t) -> Result& {
return callback_get(i, t, [](auto& elem) -> Result& { /* same implementation as get_at_index */ });
}
The key point is that types must be resolved at compile-time. In the case of a template as a callback, that callback is being instantiated for every possible type regardless of whether that instatiation is actually used at runtime. You end up with N different callback functions, one for each possible case the program could encounter. There's no analogue for a simple variable.
Therefore, you need to condense N possibilities down to the same behaviour. This can be done as above by choosing a specific type and throwing (or returning an empty optional) on a mismatch. This can also be done by returning a variant, which covers all possible types, but doesn't actually bring you any closer to overcoming the impossible part of this problem—std::visit uses the same callback mechanism where each possible type needs to be compiled against the given callback.
Let's say I have two classes which implement the same basic API, and I want to test that they are "stochastically equivalent"1, over at least over a subset of their methods.
E.g., I write my own "list" class foo:list and rather than painstakingly writing a bunch of unit tests for it, I want to compare it to std::list as a reference. That is, any sequence of operations on foo::list should produce the same results as the same sequence of std::list.
I'm OK listing the names of the operations, but hopefully not much more boilerplate than that. A generic solution that can be applied to other pairs of "behaviorally equivalent" classes is ideal.
1 By "stochastically equivalent" I mean that no differences are observed over many series of operations, which obviously falls short of a complete proof of equivalence.
In Short
Construct one foo::list and one std::list and then compare them as you perform operations on them. Really the only difference from a normal unit test is that you have two containers and instead of directly using REQUIRE() for each operation on the type you are testing, you perform the operation on the type you are testing and the reference type and then compare them. For this we assume that std::list or whatever is bug-free. We then use it as our reference point for not failing. In other words, if the operation succeeds with std::list and succeeds with foo::list, and they compare equal, the operation succeeded.
An Example
You know what the subset of operations are that you can use to compare state and I do not, so here's a mock comparison function
template <class T, class U>
bool compare_types(const T &t, const U &u)
{
bool equivalent = true;
//Generic comparisons here, like iterating over the elements to compare their values.
//Of course update equal or just return false if the comparison fails.
//If your types are not containers, perform whatever is needed to test equivalent state.
return equivalent;
}
As Jarod42 pointed out, this can get more fun and more generic, particularly if the Op f below is a lambda (C++14 needed for generic lambdas):
template <class ValueT, class RefT, class TestT, class Op>
bool compare_op_with_value(RefT &t, TestT &u, Op f, const ValueT &value)
{
if (!compare_types(t, u))
return false;
f(t, value);
f(u, value);
return compare_types(t, u);
}
Your function may return a value:
template <class ValueT, class RefT, class TestT, class Op>
bool compare_op_with_ret(RefT &t, TestT &u, Op f)
{
if (!compare_types(t, u))
return false;
ValueT ret1 = f(t);
ValueT ret2 = f(u);
return ret1 == ret2 && compare_types(t, u);
}
...and so on for dereferenceable return types, etc. You'll need to write a new comparison function for each kind of test, but that's pretty trivial. You'll need to add another template parameter for return types that are not the same (e.g. an iterator).
Then you need your test case (I subbed in std::vector as foo::list for exposition)...
TEMPLATE_TEST_CASE("StdFooCompare", "[list]", int)
{
using std_type = std::list<TestType>;
using foo_type = std::vector<TestType>;
auto initializer = {0,1,2,3,4};
std_type list1 = initializer;
foo_type list2 = initializer;
//testing insertion, using auto since insert() returns iterators
auto insert_f = [](auto list, TestType value) -> auto {
return list.insert(list.begin(), value);
};
REQUIRE(compare_op_with_value(list1, list2, insert_f, -1));
//testing front(), being explicit about the return type rather than using auto
auto front_f = [](auto list) -> TestType & {
return list.front();
};
REQUIRE(compare_op_with_ret<TestType>(list1, list2, front_f));
//continue testing along these lines
}
I could spend a couple more hours on this, but I hope you get the idea. I spent more time on this.
Note: I did not actually run this code, so consider it all pseudo-code to get the idea across, e.g. I may have missed a semicolon or some such.
Is it possible to generate new type whenever a function is called?
I've read that each lambda has its own unique type, so I've tried:
template<class T, class F> struct Tag { };
template<class T>
auto func(const T &t) -> auto
{
auto f = [] () {};
return Tag<T, decltype(f)>();
}
static_assert(!std::is_same_v<decltype(func(0)), decltype(func(1))>, "type should be different.");
But, static_assert fails.
Can I make func() return a value of different type whenever func() called regardless of type T and the value of t?
No, not when the function is called. Types are generated at compile time, not at runtime.
Have a look at the question Can the 'type' of a lambda expression be expressed? Here is a code based on an answer from there.
#include <iostream>
#include <set>
int main()
{
auto n = [](int l, int r) { return l > r; };
auto m = [](int l, int r) { return l > r; };
std::set<int, decltype(n)> s(n);
std::set<int, decltype(m)> ss(m);
std::set<int, decltype(m)> sss(m);
std::cout << (std::is_same<decltype(s), decltype(ss)>::value ? "same" : "different") << '\n';
std::cout << (std::is_same<decltype(ss), decltype(sss)>::value ? "same" : "different") << '\n';
}
Result:
different
same
C++ is a statically typed language, which means the types only exist in the source code, and there is little trace of them left in the runtime.
Lambdas are no exception - they do have unique types, but those are defined at the compile time.
Templates can indeed be used to generate new types, and that is possible because templates are evaluated at compile time and therefore only exist in the source code as well.
So the strict answer is no, you cannot generate new types when the function is called, as function calls happen in runtime.
This being said, you can achieve pretty much any desirable flexibility in C++ with some clever design, just check out some common design patterns.
Is it possible to access (read only) the variables captured by a lambda?
This doesn't work:
std::function<double (const double)> plus (const double a) {
return [a] (const double b) -> double {
return a+b;
};
}
auto plus5 = plus(5);
cout << plus5.a << endl;
auto plus( double a ) {
using R = struct {
double a;
double operator()(double b)const{return b+a;}
};
return R{std::move(a)};
}
live example.
Please note that a std::function is not a lambda, and lambda is not a std::function. They work with each other, but using one term to refer to the other is the opposite of helpful.
This is not how a lambda should be used.
The interface of a lambda is its function signature. Its captures should be considered an implementation detail and not be visible to the user.
If you want explicit access to the captures, write your own function object and expose the respective data members accordingly:
struct MyPlus {
double a;
MyPlus(double x) : a(x) {}
double operator()(const double b)
{
return a+b;
}
};
auto plus5 = MyPlus(5);
std::cout << plus5.a;
"Definitely not after storing it in a std function. Without that, I could do it with a horrible (yet legal) hack in C++17. But I would be a horrible person to tell you how, because you might use it." – Yakk
Well let's relieve Yakk's karma; here's a proof of concept of a C++14 solution which you definitely don't want to let loose in the wild:
auto magic = [a, b](auto &&... args) mutable -> decltype(auto) {
return makeOverload(
// Capture access boilerplate
[&](cap_<0>) -> auto& { return a; },
[&](cap_<1>) -> auto& { return b; },
// Actual function
[&](int p) {
return "[" + std::to_string(a) + ", " + b + "](" + std::to_string(p) + ")";
}
)(std::forward<decltype(args)>(args)...);
};
makeOverload takes any number of functors and blends them into a single one. I borrowed the idea from this blog post, with help from the comment section to make it actually work.
The resulting functor is used to tag-dispatch between the cap<N> tags and the actual parameters of the function. Thus, calling magic(cap<0>) causes it to spit out the corresponding captured variable, that is a. The actual behaviour of the function is, of course, still accessible with a normal call to magic(123).
As a bonus, the outer lambda is mutable, and the capture accessors return by reference: you actually have read-write access to the captured variables!
You can observe and interact with this creature in its natural habitat on Coliru right here.
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