C ++ 11 รองรับฟังก์ชั่นรายการลำดับสูงกว่า


13

ส่วนใหญ่ทำงานเขียนโปรแกรมภาษา (เช่น Common เสียงกระเพื่อมโครงการ / แร็กเก็ต, Clojure, Haskell, สกาล่า Ocaml, SML) สนับสนุนบางส่วนทำงานร่วมกันขั้นสูงในรายการเช่นmap, filter, takeWhile, dropWhile, foldl, foldr(ดูเช่นCommon เสียงกระเพื่อมโครงการ / แร็กเก็ต, 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 ++?


ใช่ แต่พวกเขาทำงานบนแนวคิดทั่วไปมากกว่าการใช้งานเฉพาะของรายการที่เชื่อมโยงเป็นสองเท่า เช่นเดียวกับการดำเนินงานของไพ ธ อนในพื้นที่นี้ ฉันชอบที่จะเชื่อมโยงกับโครงสร้างข้อมูลที่เฉพาะเจาะจง เคยพยายามที่จะดำเนินการเหล่านี้พูดData.Sequenceใน Haskell? มันค่อนข้างน่าเกลียด

"มันค่อนข้างน่าเกลียด": เปรียบเทียบกับอะไร
Giorgio

[a]เมื่อเทียบกับการดำเนินการเช่นเดียวกันกับ คุณต้องซ่อนฟังก์ชั่นโหมโรงแฮ็กรอบ ๆ โหมโรงหรือเลือกชื่อที่แตกต่างและใช้งานง่ายกว่า

บางทีคุณอาจถูก แต่หัวข้อของคำถามนี้คือวิธีแสดงรายการทั่วไปที่มีลำดับสูงกว่าฟังก์ชันใน C ++ ไม่ใช่วิธีใช้ฟังก์ชันแบบอะนาล็อกบน Data.Sequence ใน Haskell
Giorgio

1
@delnan ฉันจะยืนยันว่า Haskell นั้นกว้างกว่าในแนวทางของมัน Functor, FoldableและTraversableประสบความสำเร็จในครั้งนี้เป็นวิธีการที่เป็นนามธรรมที่ฉันสามารถคิด เป็นตัวอย่างของสิ่งเหล่านี้ดังนั้นคุณก็สามารถทำได้Data.Sequence เป็นผู้เชี่ยวชาญสำหรับผู้เริ่มต้น fmap (\x -> x * x) xsmapfmap
อเล็กซ์

คำตอบ:


16

ยิ่งไปกว่านั้น C ++ มีฟังก์ชั่นดังกล่าวดูที่อัลกอริทึม (หรือด้วยการเพิ่ม C ++ 11 ):

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

พวกเขาสามารถใช้กับภาชนะใด ๆ ได้อย่างง่ายดาย

ตัวอย่างเช่นรหัสของคุณสามารถแสดงเช่นนี้ (ด้วย lambdas 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 หรือไม่
Giorgio

std::transformใช้ตัววนซ้ำสองตัวดังนั้นคุณสามารถนำชิ้นส่วนของคอนเทนเนอร์ (จำไว้ว่าคุณมีตัวคำนวณแบบตัวนับซ้ำ)
m0nhawk

ดังนั้นคุณมีสองการดำเนินงานในหนึ่งเดียว: การแบ่งและใช้การแปลง
Giorgio

ก่อนหน้านี้คุณมีตัววนซ้ำสองตัวและใช้การแปลงกับองค์ประกอบระหว่างพวกเขา การทำซ้ำไม่ใช่เรื่องธรรมดาในการเขียนโปรแกรมการทำงาน
m0nhawk

2
ฉันไม่ได้พบไลบรารีดังกล่าวใน C ++ อัลกอริทึมที่ใช้ตัววนซ้ำมีประโยชน์มาก คุณสามารถทำให้กระดาษห่อของในกรณีของคุณที่ชอบ:std::transform Y<U> map(T<U>, std::function<Y(U)>)
m0nhawk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.