Üst düzey liste işlevleri için C ++ 11 desteği


13

Çoğu fonksiyonel programlama dilleri (mesela Common Lisp, Scheme / Raket, Clojure, Haskell, Scala, Ocaml, SML) gibi listelerde bazı ortak yüksek mertebeden fonksiyonları desteklemek map, filter, takeWhile, dropWhile, foldl, foldrmesela (bkz , Common Lisp, Scheme / Racket Clojure yan yana referans sayfası , Haskell , Scala , OCaml ve SML belgeleri.)

C ++ 11, listelerde eşdeğer standart yöntem veya işlevlere sahip mi? Örneğin, şu Haskell snippet'ini düşünün:

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

Modern C ++ standardında ikinci ifadeyi nasıl ifade edebilirim?

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

Yukarıda bahsedilen diğer üst düzey işlevler ne olacak?
Doğrudan C ++ ile ifade edilebilirler mi?


Evet, ancak çift bağlantılı bir listenin bu özel uygulamasından daha genel kavramlar üzerinde çalışırlar. Python'un bu alandaki operasyonları gibi. Bunu belirli bir veri yapısına bağlı olmayı tercih ederim. Data.SequenceHaskell'de bu işlemleri hiç denediniz mi? Nispeten çirkin.

“Nispeten çirkin.”: Neye kıyasla?
Giorgio

Aynı işlemle karşılaştırıldığında [a]. Başlangıç ​​işlevini gizlemeniz, başlangıçta hacklemeniz veya farklı ve daha az sezgisel bir ad seçmeniz gerekir.

Belki haklısınız, ancak bu sorunun konusu, C ++ 'ta ortak liste üst düzey işlevlerinin nasıl ifade edileceği, Haskell'deki Data.Sequence üzerinde nasıl benzer işlevlerin uygulanacağıdır.
Giorgio

1
@delnan Haskell'in yaklaşımında çok daha genel olduğunu iddia ediyorum . Functor, Foldableve Traversablebunu olabildiğince soyut bir şekilde başar. Data.Sequencebunların hepsinin bir örneğidir, yani bunu yapabilirsiniz fmap (\x -> x * x) xs. mapolduğu fmapbaşlayanlar için uzman.
Alec

Yanıtlar:


16

Dahası, C ++ bu tür işlevlere sahiptir, algoritmaya (veya C ++ 11 eklemeleriyle ) başlığa bir göz atın :

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

Herhangi bir kap ile kolayca kullanılabilirler.

Örneğin, kodunuz şu şekilde ifade edilebilir (kolay kodlama için C ++ 11 lambdas ile):

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; });

Daha az sezgisel, ancak std::transformçağrıyı kolayca yeni kapsayıcı ( movedaha iyi performans için semantik ile) döndürecek işleve sarabilirsiniz .


Teşekkürler. Birkaç gün önce yazdığım bazı kodu basitleştirmek istiyorum ve bu gerçekten çok daha kısa hale getirmeye yardımcı olabilir. Sadece küçük bir soru: neden x.begin () ve x.end () iletmeniz gerekiyor? Sadece x vektörünü geçmek için yeterli olmaz mıydı?
Giorgio

std::transformiki yineleyici alır, böylece bir kabın bir dilimini alabilirsiniz (yineleyicilerin aritmetiğiniz olduğunu unutmayın).
m0nhawk

Birinde iki işleminiz var: bir dilim almak ve bir dönüşüm uygulamak.
Giorgio

Eskiden iki yineleyiciniz var ve aralarındaki öğelere dönüşüm uyguluyorsunuz. Fonksiyonel programlamada yineleyiciler yaygın değildir.
m0nhawk

2
Bu tür kütüphanelerle karşılaşmadım, C ++ 'da yineleyici tabanlı algoritma çok kullanışlı. Sen, senin durumunda, bir sarmalayıcı yapabilirsiniz std::transformgibi: Y<U> map(T<U>, std::function<Y(U)>).
m0nhawk
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.