C ++ 11 hỗ trợ cho các chức năng danh sách bậc cao


13

Hầu hết các ngôn ngữ lập trình chức năng (ví dụ Common Lisp, Đề án / Racket, Clojure, Haskell, Scala, Ocaml, SML) hỗ trợ một số chức năng phổ biến bậc cao trên danh sách, chẳng hạn như map, filter, takeWhile, dropWhile, foldl, foldr(xem ví dụ Common Lisp, Đề án / vợt, Clojure side-by-side tờ tài liệu tham khảo , các Haskell , Scala , OCaml , và SML tài liệu.)

C ++ 11 có các phương thức hoặc hàm tiêu chuẩn tương đương trong danh sách không? Ví dụ: hãy xem xét đoạn trích Haskell sau:

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

Làm thế nào tôi có thể diễn tả biểu thức thứ hai trong C ++ tiêu chuẩn hiện đại?

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

Còn các hàm bậc cao khác được đề cập ở trên thì sao?
Họ có thể được thể hiện trực tiếp trong C ++?


Có, nhưng họ hoạt động trên các khái niệm chung hơn so với việc thực hiện cụ thể của một danh sách liên kết đôi. Hoạt động của Python trong lĩnh vực này cũng vậy. Tôi rất thích điều đó được gắn với một cấu trúc dữ liệu cụ thể. Bạn đã bao giờ thử thực hiện các thao tác này trên, nói, Data.Sequencetrong Haskell chưa? Nó tương đối xấu.

"Nó tương đối xấu.": So với cái gì?
Giorgio

So với các hoạt động tương tự trên [a]. Bạn có thể phải ẩn chức năng mở đầu, hack xung quanh khúc dạo đầu hoặc chọn một tên khác và ít trực quan hơn.

Có thể bạn đúng, nhưng chủ đề của câu hỏi này là làm thế nào để thể hiện danh sách chung các hàm bậc cao hơn trong C ++, chứ không phải cách triển khai các hàm tương tự trên Data.Sequence trong Haskell.
Giorgio

1
@delnan Tôi sẽ tranh luận rằng Haskell nói chung hơn nhiều trong cách tiếp cận của nó. Functor, FoldableTraversableđạt được điều này theo cách trừu tượng như tôi có thể nghĩ. Data.Sequencelà một ví dụ của tất cả những điều này, vì vậy bạn chỉ có thể làm fmap (\x -> x * x) xs. mapfmapchuyên ngành cho người mới bắt đầu.
Alec

Câu trả lời:


16

Thậm chí, C ++ có các chức năng như vậy, hãy xem tiêu đề thuật toán (hoặc bổ sung C ++ 11 ):

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

Chúng có thể dễ dàng được sử dụng với bất kỳ container.

Ví dụ: mã của bạn có thể được thể hiện như thế này (với C ++ 11 lambdas để mã hóa dễ dàng):

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

Ít trực quan hơn, nhưng bạn có thể dễ dàng kết thúc std::transformcuộc gọi vào chức năng sẽ trả lại container mới (với movengữ nghĩa để có hiệu suất tốt hơn).


Cảm ơn. Tôi muốn đơn giản hóa một số mã tôi đã viết vài ngày trước và điều này thực sự có thể giúp làm cho nó ngắn hơn nhiều. Chỉ một câu hỏi nhỏ: tại sao bạn cần vượt qua x.begin () và x.end ()? Sẽ không đủ để chỉ vượt qua vectơ x?
Giorgio

std::transformmất hai vòng lặp, vì vậy, bạn có thể lấy một lát của một thùng chứa (hãy nhớ rằng bạn có các vòng lặp lặp).
m0nhawk

Vì vậy, bạn có hai thao tác trong một: lấy một lát và áp dụng một phép biến đổi.
Giorgio

Trước đây bạn có hai vòng lặp và áp dụng biến đổi cho các phần tử giữa chúng. Lặp đi lặp lại không phổ biến trong lập trình chức năng.
m0nhawk

2
Tôi chưa gặp các thư viện như vậy, trong C ++, thuật toán dựa trên iterator rất hữu ích. Bạn có thể tạo một trình bao bọc, trong trường hợp của bạn, std::transformnhư : Y<U> map(T<U>, std::function<Y(U)>).
m0nhawk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.