Supporto C ++ 11 per funzioni di elenco di ordine superiore


13

La maggior parte dei linguaggi di programmazione funzionale (ad esempio Common Lisp, Scheme / Racket, Clojure, Haskell, Scala, OCaml, SML) supportano alcune funzioni comuni di ordine superiore delle liste, come ad esempio map, filter, takeWhile, dropWhile, foldl, foldr(si veda ad esempio Common Lisp, Scheme / Racket, Clojure: foglio di riferimento affiancato , Haskell , Scala , OCaml e documentazione SML .)

C ++ 11 ha metodi o funzioni standard equivalenti negli elenchi? Ad esempio, considera il seguente frammento di Haskell:

let xs = [1, 2, 3, 4, 5]
let ys = map (\x -> x * x) xs

Come posso esprimere la seconda espressione nel moderno standard C ++?

std::list<int> xs = ... // Initialize the list in some way.
std::list<int> ys = ??? // How to translate the Haskell expression?

Che dire delle altre funzioni di ordine superiore menzionate sopra?
Possono essere espressi direttamente in C ++?


Sì, ma operano su concetti più generali di quella specifica implementazione di un elenco doppiamente collegato. Come le operazioni di Python in quest'area. Preferisco di gran lunga quello di essere legato a una specifica struttura di dati. Hai mai provato a fare queste operazioni, diciamo, a Data.Sequencein Haskell? È relativamente brutto.

"È relativamente brutto.": Rispetto a cosa?
Giorgio,

Rispetto alla stessa operazione su [a]. Devi nascondere la funzione di preludio, aggirare il preludio o scegliere un nome diverso e meno intuitivo.

Forse hai ragione, ma l'argomento di questa domanda è come esprimere le funzioni di ordine superiore dell'elenco comune in C ++, non come implementare funzioni analoghe su Data.Sequence in Haskell.
Giorgio,

1
@delnan Direi che Haskell è molto più generale nel suo approccio. Functor, Foldablee Traversableraggiungere questo obiettivo nel modo più astratto che posso pensare. Data.Sequenceè un'istanza di tutti questi, quindi puoi semplicemente farlo fmap (\x -> x * x) xs. mapè fmapspecializzato per i principianti.
Alec,

Risposte:


16

Ancora di più, C ++ ha tali funzioni, dai un'occhiata all'intestazione dell'algoritmo (o con aggiunte C ++ 11 ):

std::transform
std::for_each
std::remove_copy_if

Possono essere facilmente utilizzati con qualsiasi contenitore.

Ad esempio il tuo codice può essere espresso in questo modo (con lambda C ++ 11 per una facile codifica):

std::vector<int> x = {1, 2, 3, 4, 5};
std::vector<int> y;
std::transform(x.begin(), x.end(), std::back_inserter(y), [](int elem){ return elem * elem; });

Meno intuitivo, ma puoi facilmente avvolgere la std::transformchiamata in funzione che restituirebbe un nuovo contenitore (con movesemantica per una migliore prestazione).


Grazie. Vorrei semplificare un po 'di codice che ho scritto qualche giorno fa e questo potrebbe davvero contribuire a renderlo molto più breve. Solo una piccola domanda: perché devi passare x.begin () e x.end ()? Non sarebbe sufficiente passare semplicemente il vettore x?
Giorgio,

std::transformprende due iteratori, quindi puoi prendere una fetta di un contenitore (ricorda che hai gli iteratori aritmetici).
m0nhawk,

Quindi hai due operazioni in una: prendere una fetta e applicare una trasformazione.
Giorgio,

Precedentemente hai due iteratori e applica la trasformazione agli elementi tra loro. Iteratori non sono comuni nella programmazione funzionale.
m0nhawk,

2
Non ho incontrato tali librerie, in C ++ l'algoritmo basato su iteratore è molto utile. Si può fare un wrapper di, nel tuo caso, std::transformcome: Y<U> map(T<U>, std::function<Y(U)>).
m0nhawk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.