问题
I am trying to implement the K combinator from the SK combinator calculus in C++. The K combinator is a higher-order function that basically takes some value x
, and returns something which in turn takes a value y
and returns x
from it. In other words,
K(x)(y) == x
or step-by-step:
intermediate = K(x)
intermediate(y) == x
The ability to treat K(x)
as a thing-in-itself, independent of y
, is essential. Furthermore, it should not be necessary to specify the type of y
when simply creating K(x)
without calling it on y
. The type of y
can be specified once K(x)(y)
is being evaluated somewhere in the code.
I am trying to fix the code I wrote which attempts to implement the K combinator:
#include <iostream>
template<class A>
template<class B>
auto K = [](A x) {
return [=](B y) {
return x;
};
};
int main()
{
std::cout << "Hello world!\n";
auto Kx = K<int>(3);
auto Kxy = Kx<float>(4.5);
std::cout << Kxy << std::endl;
}
It outputs error: extraneous template parameter list in template specialization or out-of-line template definition
. I have tried adjusting the template parameters and moving them around to no avail. Does anyone know how I could fix this error?
回答1:
Lambdas cannot be templates. You can do this though:
#include <iostream>
auto K = [](auto x) {
return [=](auto y) {
return x;
};
};
int main()
{
std::cout << "Hello world!\n";
auto Kx = K(3);
auto Kxy = Kx(4.5);
std::cout << Kxy << std::endl;
}
These are called generic lambdas (exist since C++14), and are basically what you want. Their operator()
is template for each auto
parameter.
回答2:
This is quite possible even of you don't have C++14 – just remember that lambdas are merely a shortcut notation for functor objects. We can therefore create an object representing the intermediate value:
template<class A>
class Intermediate {
A m_a;
public:
explicit Intermediate(const A& a)
: m_a(a)
{}
template<class B>
A operator()(const B&) const
{ return m_a; }
};
template<class A>
Intermediate<A> K(const A& a)
{ return Intermediate<A>(a); }
The separate K
function is necessary for template argument deduction so that we can write K(x)(y)
.
回答3:
You can "solve" it by the following change:
template<class A, class B>
auto K = [](A x) {
return [=](B y) {
return x;
};
};
However, you then need to change the calls as well:
auto Kx = K<int, float>(3);
auto Kxy = Kx(4.5);
As an explaining note, while lambdas themselves can't be templated, but from C++14 variables can, and what I'm doing is declaring K
as a templated variable, it just so happens that the variable is declared as a lambda object.
来源:https://stackoverflow.com/questions/35403540/implementing-the-typed-k-combinator-in-c