Dukungan C ++ 11 untuk fungsi daftar tingkat tinggi

13

Kebanyakan bahasa pemrograman fungsional (misalnya Common Lisp, Scheme / Racket, Clojure, Haskell, Scala, Ocaml, SML) mendukung beberapa fungsi umum tingkat tinggi pada daftar, seperti map, filter, takeWhile, dropWhile, foldl, foldr(lihat misalnya Common Lisp, Scheme / Racket, Clojure lembar referensi berdampingan , Haskell , Scala , OCaml , dan dokumentasi SML .)

Apakah C ++ 11 memiliki metode atau fungsi standar yang setara pada daftar? Misalnya, perhatikan cuplikan Haskell berikut:

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

Bagaimana saya bisa mengekspresikan ekspresi kedua dalam C ++ standar modern?

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

Bagaimana dengan fungsi tingkat tinggi lainnya yang disebutkan di atas?
Bisakah mereka diekspresikan secara langsung dalam C ++?

Giorgio
sumber
Ya, tetapi mereka beroperasi pada konsep yang lebih umum daripada implementasi spesifik dari daftar yang ditautkan dua kali lipat. Seperti halnya operasi Python di area ini. Saya lebih suka itu terikat pada struktur data tertentu. Pernah mencoba melakukan operasi ini pada, katakanlah, Data.Sequencedi Haskell? Ini relatif jelek.
"Ini relatif jelek.": Dibandingkan dengan apa?
Giorgio
Dibandingkan dengan operasi yang sama aktif [a]. Anda juga harus menyembunyikan fungsi pembuka, meretas pendahuluan, atau memilih nama yang berbeda dan kurang intuitif.
Mungkin Anda benar, tetapi topik dari pertanyaan ini adalah bagaimana mengekspresikan daftar umum fungsi tingkat tinggi di C ++, bukan bagaimana mengimplementasikan fungsi analog pada Data.Sequence di Haskell.
Giorgio
1
@ Dave Saya berpendapat bahwa Haskell jauh lebih umum dalam pendekatannya. Functor,, Foldabledan Traversablecapai ini dengan cara abstrak yang saya bisa pikirkan. Data.Sequenceadalah contoh dari semua ini, jadi Anda bisa melakukannya fmap (\x -> x * x) xs. mapadalah fmapkhusus untuk pemula.
Alec

Jawaban:

16

Terlebih lagi, C ++ memiliki fungsi seperti itu, lihat header algoritme (atau dengan tambahan C ++ 11 ):

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

Mereka dapat dengan mudah digunakan dengan wadah apa pun.

Misalnya kode Anda dapat diekspresikan seperti ini (dengan C ++ 11 lambdas untuk pengodean yang mudah):

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

Kurang intuitif, tetapi Anda dapat dengan mudah membungkus std::transformpanggilan menjadi fungsi yang akan mengembalikan wadah baru (dengan movesemantik untuk kinerja yang lebih baik).

m0nhawk
sumber
Terima kasih. Saya ingin menyederhanakan beberapa kode yang saya tulis beberapa hari yang lalu dan ini sangat membantu membuatnya menjadi lebih singkat. Hanya satu pertanyaan kecil: mengapa Anda harus lulus x.begin () dan x.end ()? Tidak cukup hanya melewatkan vektor x?
Giorgio
std::transformmengambil dua iterator, jadi, Anda dapat mengambil sepotong wadah (ingat bahwa Anda memiliki iterator aritmatika).
m0nhawk
Jadi, Anda memiliki dua operasi dalam satu: mengambil sepotong, dan menerapkan transformasi.
Giorgio
Sebelumnya Anda memiliki dua iterator dan menerapkan transformasi ke elemen di antara mereka. Iterator tidak umum dalam pemrograman fungsional.
m0nhawk
2
Saya belum pernah bertemu perpustakaan seperti itu, di C ++ algoritma berbasis iterator sangat berguna. Anda dapat membuat pembungkus dari, dalam kasus Anda, std::transformseperti: Y<U> map(T<U>, std::function<Y(U)>).
m0nhawk