2010-10-11 17 views
23

Potrzebuję analogu funkcji Haskella do funkcji foldl, aby złożyć wszystkie pojemniki STL. Oczekiwany podpis jest następujący:Jak złożyć pojemnik STL?

template Iterator, FoldingFunction, Result 
Result foldl(
    Iterator begin, 
    Iterator end, 
    FoldingFunction f, 
    Result initValue); 

Standardowy STL nie ma takiej funkcji. Czy Boost ma jakieś?

Wiem, że jest to łatwe do wdrożenia, ale chciałbym się dowiedzieć, czy istnieje jakaś gotowa, wystandaryzowana implementacja.

I jeszcze jedno pytanie: jak zwykle składa się listy danych w C++/STL?

+3

Co, u licha, masz na myśli przez "składanie"? – Konrad

+4

@Konrad: [fold] (http://en.wikipedia.org/wiki/Fold_%28higher-order_function%29) = zmniejsz = gromadz. – kennytm

+3

@Konrad - przetwarzaj strukturę danych w określonej kolejności i buduj wartość zwracaną. http://www.haskell.org/haskellwiki/Fold – DumbCoder

Odpowiedz

37

STL ma taką funkcję: std::accumulate. Jednak jest w nagłówku <numeric>, a nie <algorithm>.

Faktycznie Wikipedia page on "Fold" już wymienione funkcje foldl/ na większości języków programowania, w tym C++.

+0

@KennyTM: Szczególnie dziękuję za odniesienie do Wiki. – Andrey

+0

Zauważ, że 'kumuluje' używa' argumentu_wartości' argumentów iteratora dla wewnętrznej zmiennej akumulatora, pomimo akceptowania i zwracania odrębnego typu i dopuszczania innych typów wciąż w argumencie funktora. – Potatoswatter

+0

@Potatoswatter: Nie widzę tego z definicji kumulacji: TYPE akumuluj (start_iterator start, input_iterator end, TYPE val, BinaryFunction f); – Andrey

4

Czy obejrzałeś std::accumulate w nagłówku <numeric>?

+0

To 'std :: accumulate'. Jest w przestrzeni nazw 'std', ale w nagłówku' '. :) – jalf

+0

@alff keep 'em coming. Jedyny sposób, abym pozostał w kolejce. : P – wheaties

0

Mimo, że std:: accumulate wydaje się być najlepszym kandydatem, myślę, że wymaganie to można osiągnąć również za pomocą starego dobrego for_each.

Wziąłem przykłady z linku w answer of KennyTM i przetłumaczyłem je wszystkie na for_each. The full code is posted at codepad po jakiś fragment:

struct result_functor { 
    result_functor(int initial, int multiplier) : 
     result_(initial), multiplier_(multiplier) { 
    } 
    int operator()(int x) { 
     result_ += multiplier_ * x; 
     return result_; 
    } 
    int result_; 
    int multiplier_; 
}; 

const int init = 100; 
const int numbers[] = { 10, 20, 30 }; 

const int accum_sum = std::accumulate(numbers, numbers + 3, init); 
const result_functor for_sum = for_each( 
    numbers, numbers + 3, result_functor(init, +1)); 
assert(accum_sum == for_sum.result_); 
+0

Stateful functor 'result_functor' oznacza niezdefiniowane zachowanie. – Loom

+0

@Loom Ta odpowiedź sugeruje, że funktory stanowe są dobre dla 'std :: for_each': http://stackoverflow.com/a/6113053/2348315, czy jest niepoprawny? – PeterSW

1

oto moja realizacja za pomocą std :: gromadzić

template<typename collection, typename operation> 
typename collection::value_type reduce(collection col, operation op) 
{ 
    return accumulate(col.begin(), col.end(), typename collection::value_type(), op); 
} 

reduce środki te krotnie w Haskell. A ten szablon funkcji może sprawić, że program będzie bardziej funkcjonalny :)

+0

Użycie 'begin (col)' i 'end (col)' będzie bardziej ogólne, ale nadal ta funkcja jest dość niepotrzebna, ponieważ 'accumulate' można łatwo wywołać bezpośrednio. – sim642

-1

dlaczego nie tylko;

b_t foldl(b_t (*f)(b_t,a_t),b_t base_case,a_t * in_list){ 
int l = sizeof(inList)/sizeof(a_t); 
b_t carry = base_case; 
for(int i = 0;i<l;i++){ 
    carry = f(carry,in_list[i]); 
    } 
return carry; 
} 

lub rekurencyjnie; // może mógłbyś mi pomóc z poprawną składnią ...

b_t foldl(b_t (*f)(b_t,a_t),b_t base_case,a_t * in_list){ 
return foldl(f,f(base_case,in_list[0]),in_list + 1);  
} 
+2

Ponieważ działa to tylko z 'b_t',' a_t' i wskaźnikami funkcji. Ponadto jest mniej wiarygodny niż znacznie szerzej stosowana i sprawdzona alternatywa, którą można znaleźć w standardowych implementacjach bibliotek. – PeterSW