C ++ 11 підтримка функцій списку вищого порядку


13

Більшість функціональних мов програмування (наприклад , Common Lisp, Scheme / ракетки, Clojure, Haskell, Scala, Ocaml, SML) підтримують деякі загальні функції вищого порядку в списках, такі як map, filter, takeWhile, dropWhile, foldl, foldr(см , наприклад , Common Lisp, Scheme / Ракетка, Довідковий лист Clojure , документація Haskell , Scala , OCaml та документація SML .)

Чи C ++ 11 має еквівалентні стандартні методи або функції у списках? Наприклад, розглянемо наступний фрагмент Haskell:

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

Як я можу виразити другий вираз у сучасному стандарті C ++?

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

А що з іншими згаданими вище функціями вищого порядку?
Чи можуть вони бути безпосередньо виражені в C ++?


Так, але вони працюють на більш загальних концепціях, ніж на конкретній реалізації подвійно пов'язаного списку. Як і дії Python в цій області. Я дуже вважаю за краще прив’язувати до конкретної структури даних. Ви коли-небудь намагалися робити ці операції, скажімо, Data.Sequenceв Haskell? Це порівняно некрасиво.

"Це порівняно некрасиво.": У порівнянні з чим?
Джорджіо

У порівнянні з тією ж операцією на [a]. Вам або потрібно приховати функцію прелюдії, зламати прелюдію або вибрати інше і менш інтуїтивне ім’я.

Можливо, ви маєте рацію, але тема цього питання полягає в тому, як висловити загальний список функцій вищого порядку в C ++, а не як реалізувати аналогічні функції на Data.Sequence в Haskell.
Джорджіо

1
@delnan Я б заперечував, що Haskell набагато більш загальний у своєму підході. Functor, Foldableі Traversableдосягти цього настільки абстрактно, як я можу подумати. Data.Sequenceє екземпляром всього цього, тому ви можете просто зробити fmap (\x -> x * x) xs. mapце fmapспеціалізований для початківців.
Алек

Відповіді:


16

Навіть більше, у C ++ є такі функції, погляньте на заголовок алгоритму (або з додатками C ++ 11 ):

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

Їх можна легко використовувати з будь-яким контейнером.

Наприклад, ваш код може бути виражений так (з C ++ 11 лямбда для легкого кодування):

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

Менш інтуїтивно зрозумілий, але ви можете легко std::transformперетворити виклик у функцію, яка б повернула новий контейнер (із moveсемантикою для кращої продуктивності).


Спасибі. Я хотів би спростити деякий код, який я написав кілька днів тому, і це дійсно може допомогти зробити його набагато коротшим. Лише одне невелике запитання: навіщо вам передавати x.begin () та x.end ()? Не буде достатньо просто передати вектор x?
Джорджіо

std::transformбере два ітератори, отже, ви можете взяти фрагмент контейнера (пам’ятайте, що у вас є арифметика ітераторів).
m0nhawk

Отже, у вас є дві операції в одній: взяти фрагмент і застосувати перетворення.
Джорджіо

Раніше у вас є два ітератори і застосовуєте перетворення до елементів між ними. Ітератори не поширені у функціональному програмуванні.
m0nhawk

2
Я не зустрічав таких бібліотек, в C ++ дуже корисний алгоритм на основі ітератора. Ви можете зробити обгортку, в вашому випадку, std::transformяк: Y<U> map(T<U>, std::function<Y(U)>).
m0nhawk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.