如何用C ++进行精简?

时间:2020-03-06 14:54:36  来源:igfitidea点击:

什么是咖喱?

如何用C ++进行精简?

请解释STL容器中的粘合剂吗?

解决方案

简而言之,currying取一个函数f(x,y)并给定一个固定的Y,给出一个新函数g(x),其中

g(x) == f(x, Y)

在仅提供一个参数的情况下,可以调用此新函数,并将该调用传递给带有固定Y参数的原始f函数。

STL中的活页夹允许我们对C ++函数执行此操作。例如:

#include <functional>
#include <iostream>
#include <vector>

using namespace std;

// declare a binary function object
class adder: public binary_function<int, int, int> {
public:
    int operator()(int x, int y) const
    {
        return x + y;
    }
};

int main()
{
    // initialise some sample data
    vector<int> a, b;
    a.push_back(1);
    a.push_back(2);
    a.push_back(3);

    // here we declare a function object f and try it out
    adder f;
    cout << "f(2, 3) = " << f(2, 3) << endl;

    // transform() expects a function with one argument, so we use
    // bind2nd to make a new function based on f, that takes one
    // argument and adds 5 to it
    transform(a.begin(), a.end(), back_inserter(b), bind2nd(f, 5));

    // output b to see what we got
    cout << "b = [" << endl;
    for (vector<int>::iterator i = b.begin(); i != b.end(); ++i) {
        cout << "  " << *i << endl;
    }
    cout << "]" << endl;

    return 0;
}

咖喱化是一种减少将多个参数转换为嵌套函数的函数的嵌套方法,每个嵌套函数分别具有一个参数:

full = (lambda a, b, c: (a + b + c))
print full (1, 2, 3) # print 6

# Curried style
curried = (lambda a: (lambda b: (lambda c: (a + b + c))))
print curried (1)(2)(3) # print 6

Currying很好,因为我们可以定义一些函数,这些函数只是使用预定义的值将其他函数包装起来,然后传递简化的函数。 C ++ STL绑定器在C ++中提供了此实现。

看一下Boost.Bind,它使Greg所示的过程更加通用:

transform(a.begin(), a.end(), back_inserter(b), bind(f, _1, 5));

这会将5绑定到f的第二个参数。

值得注意的是,这并非易事(而是部分应用)。但是,在C ++中,以常规方式使用currying很难(实际上,直到最近才有可能实现),并且经常使用部分应用程序。

使用tr1简化Gregg的示例:

#include <functional> 
using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;

int f(int, int);
..
int main(){
    function<int(int)> g     = bind(f, _1, 5); // g(x) == f(x, 5)
    function<int(int)> h     = bind(f, 2, _1); // h(x) == f(2, x)
    function<int(int,int)> j = bind(g, _2);    // j(x,y) == g(y)
}

Tr1功能组件使我们可以用C ++编写功能丰富的代码。同样,C ++ 0x将允许内联lambda函数也可以做到这一点:

int f(int, int);
..
int main(){
    auto g = [](int x){ return f(x,5); };      // g(x) == f(x, 5)
    auto h = [](int x){ return f(2,x); };      // h(x) == f(2, x)
    auto j = [](int x, int y){ return g(y); }; // j(x,y) == g(y)
}

尽管C ++没有提供某些面向功能的编程语言所执行的丰富的副作用分析,但const分析和C ++ 0x lambda语法可以:

struct foo{
    int x;
    int operator()(int y) const {
        x = 42; // error!  const function can't modify members
    }
};
..
int main(){
    int x;
    auto f = [](int y){ x = 42; }; // error! lambdas don't capture by default.
}

希望能有所帮助。