2016-09-13 36 views
5

Mam następujący kod. Czy możesz mi wytłumaczyć, jak to działa?C++ 11: lambda, currying

template<typename Function, typename... Arguments> 
auto curry(Function func, Arguments... args) { 
    return [=](auto... rest) { 
     return func(args..., rest...); 
    }; 
} 

int main() { 
    auto add = [](auto x, auto y) { 
     return x + y; 
    }; 
    auto add4 = curry(add, 4); 
    std::cout << add4(3) << '\n'; //output: 7. (Ok) 

} 
+1

Czy masz jakieś informacje na temat tego, czego nie rozumiesz? – Hayt

Odpowiedz

10

Po pierwsze, trzeba wiedzieć, co currying to, czy w swoim pytaniu, to specjalnie przypadek partial application (do którego Zmiękczanie jest związane, ale nieco inaczej).

Zasadniczo oznacza to zmniejszenie funkcja z pewnej liczby parametrów, aby utworzyć inną funkcję niektóre wartości parametru trwałych.

ja swoje przykładowa, oryginalna funkcja jest add(x,y) który ma dwa parametry x i y. zmniejszyć arity z funkcji dodawania, ustawiając x do 4 i utworzyć zmniejszenia funkcji add4(y) np

ADD4 (Y) = dodatek (x, y) gdzie X = 4

Jak to osiągnąć w twoim kodzie C++? Przy pomocy funkcjiszablonów warstwowych, funkcji warstwowych i funkcji lambda.

Lambda functions są w języku C++ od C++ 11. W istocie są to anonimowe funkcje tworzone w locie, które można przechowywać w zmiennej. Utworzyć add jako lambda w main():

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

Jeden uznaje lambda przez wzór [] (list-of-arguments) {function-body};

Uwaga: [] nie zawsze jest pusta, patrz „przechwytywanie zmiennych” there będziemy wracać do to później.

Teraz celu FUNCTION curry jest wziąć jedną z tych lambdas funkcji func i pewnej liczby wartości jako argumentów i zdefiniować nową funkcję przez przypisywania wartości, w kolejności, do pierwszych argumentów func .

W „pewna liczba argumentów” mechanizm jest dozwolony przez variadic template argumentu Arguments... args, która pozwala wywołać szablon z dowolnej liczby typów jako parametrów szablonu (tak długo, jak są one znane jako kompilacji). W naszym przypadku przekazany argument wynosi 4, więc Arguments... args zostanie zastąpiony przez int, a instancja curry przyjmie jako parametry lambda i int.

Jeśli spojrzymy na kodzie curry, widzimy, że jest to tylko sama funkcja lambda (jest to variadic function, podobnie jak printf()), którego jedynym celem jest, aby złączyć argumenty, których wartość została już ustalona podczas uruchamianiu tego template (args...) oraz te, których wartość jest przekazywana jako argumenty funkcji curried (rest...).

Znak [=] to specjalna funkcja przechwytywania dla funkcji lambda, która umożliwia użycie wszystkich zmiennych lokalnych w ciele funkcji (tutaj umożliwia użycie args).

więc owinąć go, oto co się dzieje w twojej głównej funkcji:

  1. utworzyć zmienną o nazwie add który zawiera lambda funkcję, biorąc dwa argumenty i dodając je.
  2. Po wywołaniu curry(add,4) tworzysz instancję szablonu curry.
    • Pierwszy parametr szablonu Function jest typu add (lambda przy dwóch int i zwrócenie int)
    • drugi zestaw parametrów zmiennej liczbie argumentów zawiera tylko jeden typ: typ 4 tj int

Utworzona funkcja curry wygląda następująco:

curry((int,int)->(int) func, int arg){ 
    return [=](auto... rest) {return func(arg, rest...);}; 
} 

Pamiętaj, że nigdy nie widzisz tych typów z powodu auto i odjęcia typu szablonu.

  1. wtedy nazwać instancję func = add i arg = 4

  2. zapisać wynik tej instancji w add4 który jest obecnie N przyjmuje jeden parametr. Następnie można wywołać add4 z 3 jako argument (rest... jest 3), który będzie następnie zadzwonić add(4,3) i powrócić 7.

Zauważ, że technicznie można spróbować zadzwonić add4 z więcej niż jednego argumentu, ponieważ funkcja curry jest funkcją variadic. Kompilator zakończy się niepowodzeniem, gdy się zorientuje, że nie ma miejsca na dodatkowe argumenty podczas wywoływania add (zobacz to: here)

+0

Wielkie dzięki! Teraz czytasz! Napisałeś dużo :) – Cfon

+5

Należy zauważyć, że kod OP nie jest curry, ale raczej częściowa aplikacja. Wiele osób jest zdezorientowanych między tymi dwoma. "Currying" odnosi się do przyjęcia funkcji N argumentów i przekształcenia jej w łańcuch N funkcji o 1 argumencie. – Yakk

+0

Tak, masz rację. W moim przypadku to częściowe zastosowanie. – Cfon