Implementing the (typed) K combinator in C++

爷,独闯天下 提交于 2019-12-23 18:27:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!