55

カリー化とは?

C ++でカリー化を行うにはどうすればよいですか?

STL コンテナのバインダーについて説明してください。

4

10 に答える 10

41

要するに、カリー化は関数f(x, y)を取り、固定された を指定するとY、新しい関数g(x)が得られます。

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

この新しい関数は、引数が 1 つしか指定されていない状況で呼び出すことができ、その呼び出しをf固定Y引数で元の関数に渡します。

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;
}
于 2008-09-30T06:59:57.223 に答える
19

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 では、インライン ラムダ関数でこれを行うこともできます。

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 ラムダ構文が役立ちます。

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.
}

それが役立つことを願っています。

于 2008-10-01T23:53:56.450 に答える
14

Greg が示したプロセスをより用途の広いものにするBoost.Bindを見てください。

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

これはの 2 番目の引数にバインド5されます。f

これはカリー化ではないことに注意してください(代わりに、部分的な適用です)。ただし、一般的な方法でカリー化を使用することは C++ では難しく (実際、それが可能になったのはごく最近のことです)、代わりに部分適用がよく使用されます。

于 2008-09-30T08:44:25.770 に答える
11

他の回答はバインダーをうまく説明しているので、ここではその部分を繰り返しません。ここでは、C++0x でラムダを使用してカリー化と部分適用を実行する方法のみを示します。

コード例: (コメントで説明)

#include <iostream>
#include <functional>

using namespace std;

const function<int(int, int)> & simple_add = 
  [](int a, int b) -> int {
    return a + b;
  };

const function<function<int(int)>(int)> & curried_add = 
  [](int a) -> function<int(int)> {
    return [a](int b) -> int {
      return a + b;
    };
  };

int main() {
  // Demonstrating simple_add
  cout << simple_add(4, 5) << endl; // prints 9

  // Demonstrating curried_add
  cout << curried_add(4)(5) << endl; // prints 9

  // Create a partially applied function from curried_add
  const auto & add_4 = curried_add(4);
  cout << add_4(5) << endl; // prints 9
}
于 2011-05-26T11:49:30.657 に答える
11

C++14 を使用している場合は、非常に簡単です。

template<typename Function, typename... Arguments>
auto curry(Function function, Arguments... args) {
    return [=](auto... rest) {
        return function(args..., rest...);
    }; // don't forget semicolumn
}

その後、次のように使用できます。

auto add = [](auto x, auto y) { return x + y; }

// curry 4 into add
auto add4 = curry(add, 4);

add4(6); // 10
于 2014-10-06T10:06:40.287 に答える
6

カリー化は、複数の引数を取る関数を、それぞれ 1 つの引数を持つネストされた関数のシーケンスに縮小する方法です。

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

カリー化は、事前定義された値を持つ他の関数の単なるラッパーである関数を定義し、単純化された関数を渡すことができるため便利です。C++ STL バインダーは、これを C++ で実装します。

于 2008-09-30T07:00:10.513 に答える
2

これらのリンクは関連しています:

ウィキペディアのラムダ計算ページには、カリー化の明確な例があります
http://en.wikipedia.org/wiki/Lambda_calculus#Motivation

この論文では、C/C++ でのカリー化について扱います
http://asg.unige.ch/site/papers/Dami91a.pdf

于 2011-10-29T18:19:51.390 に答える