ฟีเจอร์ของฟังก์ชั่นอะไรที่คุ้มค่ากับความสับสน OOP เล็กน้อยเพื่อประโยชน์ที่พวกเขานำมา?


13

หลังจากเรียนรู้การเขียนโปรแกรมที่ใช้งานได้ใน Haskell และ F # กระบวนทัศน์ OOP ดูเหมือนว่าจะย้อนกลับไปพร้อมกับคลาสอินเทอร์เฟซวัตถุ FP ด้านใดที่ฉันสามารถนำไปใช้ในการทำงานที่เพื่อนร่วมงานของฉันสามารถเข้าใจได้ สไตล์ FP ใด ๆ ที่ควรค่าแก่การพูดคุยกับเจ้านายของฉันเกี่ยวกับการฝึกสอนทีมของฉันใหม่

ลักษณะที่เป็นไปได้ของ FP:

  • การเปลี่ยนไม่ได้
  • การประยุกต์ใช้บางส่วนและการแกง
  • ฟังก์ชั่นชั้นหนึ่ง (ตัวชี้ฟังก์ชั่น / วัตถุการทำงาน / รูปแบบกลยุทธ์)
  • การประเมินผลขี้เกียจ (และ Monads)
  • ฟังก์ชั่นบริสุทธิ์ (ไม่มีผลข้างเคียง)
  • นิพจน์ (เทียบกับข้อความ - แต่ละบรรทัดของโค้ดจะสร้างค่าแทนหรือนอกเหนือจากการทำให้เกิดผลข้างเคียง)
  • recursion
  • การจับคู่รูปแบบ

มันเป็นฟรีสำหรับทุกสิ่งที่เราสามารถทำอะไรก็ได้ที่ภาษาโปรแกรมรองรับจนถึงขีด จำกัด ที่ภาษานั้นรองรับหรือไม่ หรือมีแนวทางที่ดีกว่า


6
ฉันมีประสบการณ์ที่คล้ายกัน หลังจากนั้นประมาณ 2 เดือนฉันก็เริ่มรู้สึกว่า "สิ่งที่แมปกับวัตถุ" และ "สิ่งที่แมปไปยังฟังก์ชั่น" ค่อนข้างดี ช่วยในการแฮ็คอย่างจริงจังในภาษาที่รองรับทั้งสองอย่าง ในตอนท้ายของทักษะทั้ง FP และ OOP ของฉันได้รับการปรับปรุงอย่างมากมาย
Daniel Gratzer

3
FWIW, Linq เป็นทั้งการทำงานและขี้เกียจและคุณสามารถจำลองการเขียนโปรแกรมการทำงานใน C # โดยใช้วิธีการคงที่และหลีกเลี่ยงการคงอยู่ของรัฐ
Robert Harvey

1
ณ จุดนี้คุณควรอ่านSICP มันฟรีและเขียนได้ดี เป็นการเปรียบเทียบที่ดีระหว่างกระบวนทัศน์ทั้งสอง
Simon Bergot

4
FP และ OOP อยู่ในเวลาเดียวกันในบางแง่มุมและในบางแง่มุมคู่ OOP เป็นเรื่องเกี่ยวกับข้อมูลนามธรรม FP เป็นเรื่องเกี่ยวกับ (การไม่มี) ของผลข้างเคียง ไม่ว่าคุณจะมีผลข้างเคียงหรือไม่ก็ตามนั้นขึ้นอยู่กับการสรุปข้อมูลของคุณ แลมบ์ดาแคลคูลัสเป็นทั้งฟังก์ชั่นและเชิงวัตถุ ใช่ FP มักใช้ประเภทข้อมูลนามธรรมไม่ใช่วัตถุ แต่คุณสามารถใช้วัตถุแทนได้โดยไม่ต้องมี FP น้อยกว่า OTOH นอกจากนี้ยังมีความสัมพันธ์ที่ลึกล้ำ: ฟังก์ชั่น isomorphic กับวัตถุที่มีเพียงวิธีเดียว (นั่นคือวิธีที่พวกเขา "ปลอม" ใน Java และดำเนินการใน Java8, ...
Jörg W Mittag

3
ฉันคิดว่าคำถามที่แข็งแกร่งที่สุดของคุณเกี่ยวกับความสามารถในการอ่าน "สไตล์การเขียนโปรแกรมเชิงหน้าที่มีความเหมาะสมเท่าไรที่จะนำมาทำงานที่ร้าน Object Oriented" หรือฟังก์ชั่นการใช้งานอะไรที่คุ้มค่ากับความสับสน OOP เล็กน้อยเพื่อประโยชน์ที่พวกเขานำมา
GlenPeterson

คำตอบ:


13

ฟังก์ชั่นการเขียนโปรแกรมเป็นกระบวนทัศน์ที่แตกต่างจากการเขียนโปรแกรมเชิงวัตถุ (ความคิดที่แตกต่างและวิธีคิดต่าง ๆ เกี่ยวกับโปรแกรม) คุณเริ่มตระหนักว่าที่นี่มีมากกว่าหนึ่งวิธี (เชิงวัตถุ) เพื่อคิดเกี่ยวกับปัญหาและแนวทางแก้ไข มีคนอื่น ๆ (การเขียนโปรแกรมขั้นตอนและทั่วไปมาถึงใจ) วิธีที่คุณตอบสนองต่อความรู้ใหม่นี้ไม่ว่าคุณจะยอมรับและรวมเครื่องมือและวิธีการใหม่ ๆ เหล่านี้เข้ากับชุดทักษะของคุณจะเป็นตัวกำหนดว่าคุณจะเติบโตและกลายเป็นนักพัฒนาที่สมบูรณ์และมีทักษะมากขึ้น

เราทุกคนได้รับการฝึกฝนให้จัดการและรู้สึกสบายใจกับความซับซ้อนในระดับหนึ่ง ผมชอบที่จะเรียกสิ่งนี้ว่าบุคคลhrairขีด จำกัด (จาก Watership Down, วิธีสูงคุณสามารถนับ) มันเป็นสิ่งที่ดีที่จะขยายความคิดของคุณความสามารถในการพิจารณาตัวเลือกเพิ่มเติมและมีเครื่องมือเพิ่มเติมในการเข้าถึงและแก้ไขปัญหา แต่มันเป็นการเปลี่ยนแปลงและดึงคุณออกจากเขตความสะดวกสบายของคุณ

ปัญหาหนึ่งที่คุณอาจพบคือคุณจะมีเนื้อหาน้อยลงเพื่อติดตามฝูงชน "ทุกอย่างเป็นวัตถุ" คุณอาจต้องพัฒนาความอดทนเมื่อคุณทำงานกับคนที่อาจไม่เข้าใจ (หรือต้องการที่จะเข้าใจ) ว่าทำไมการพัฒนาซอฟต์แวร์ที่ใช้งานได้ดีสำหรับปัญหาบางประการ เช่นเดียวกับวิธีการเขียนโปรแกรมทั่วไปที่ทำงานได้ดีสำหรับปัญหาบางอย่าง

โชคดี!


3
ฉันต้องการเพิ่มว่าสามารถเข้าใจแนวคิด OOP แบบดั้งเดิมได้ดีขึ้นเมื่อทำงานกับภาษาที่ใช้งานได้เช่น Haskell หรือ Clojure โดยส่วนตัวแล้วฉันก็รู้ว่า polymorphism เป็นแนวคิดที่สำคัญ (การเชื่อมต่อใน Java หรือ typeclasses ใน Haskell) ในขณะที่การสืบทอด (สิ่งที่ฉันคิดว่าเป็นแนวคิดที่กำหนด) เป็นสิ่งที่แปลกประหลาด
wirrbel

6

การเขียนโปรแกรมเชิงฟังก์ชั่นให้ประโยชน์อย่างแท้จริงในเชิงปฏิบัติมากขึ้นในการเขียนโค้ดประจำวัน: คุณสมบัติบางอย่างมีความทนทานที่ดีเพราะรหัสที่คุณเขียนน้อยลงความล้มเหลวน้อยลงและการบำรุงรักษาน้อยลง

ในฐานะนักคณิตศาสตร์ฉันพบว่าสิ่งต่าง ๆ ที่น่าสนใจ แต่มักจะมีประโยชน์เมื่อออกแบบแอปพลิเคชัน: โครงสร้างเหล่านี้สามารถเข้ารหัสในโครงสร้างของโปรแกรมจำนวนมากไม่แปรเปลี่ยนของโปรแกรมโดยไม่ต้องแทนค่าคงที่เหล่านี้ด้วยตัวแปร

ชุดโปรดของฉันอาจดูเล็กน้อย แต่ฉันเชื่อว่ามันมีผลกระทบต่อการผลิตสูงมาก การรวมกันนี้เป็นบางส่วนของแอปพลิเคชันและ Curryingและฟังก์ชั่นชั้นหนึ่งซึ่งฉันจะ relabel ไม่เคยเขียน for-loop อีกครั้ง : แทนที่จะส่งเนื้อความของลูปไปที่ฟังก์ชันวนซ้ำหรือการแม็พ ฉันเพิ่งได้รับการว่าจ้างงาน C ++ และฉันสังเกตเห็นอย่างน่าประหลาดใจว่าฉันหมดนิสัยในการเขียน เพื่อลูป!

การรวมกันของการเรียกซ้ำและการจับคู่รูปแบบทำลายความต้องการของรูปแบบการออกแบบของผู้เข้าชมนั้น เพียงเปรียบเทียบรหัสที่คุณต้องการตั้งโปรแกรมผู้ประเมินของนิพจน์บูลีน: ในภาษาโปรแกรมที่ใช้งานได้ควรมีโค้ดประมาณ 15 บรรทัดใน OOP สิ่งที่ถูกต้องคือการใช้รูปแบบการออกแบบของผู้เข้าชมซึ่งเปลี่ยนตัวอย่างของเล่นใน เรียงความที่กว้างขวาง ข้อดีชัดเจนและฉันไม่ได้ตระหนักถึงความไม่สะดวกใด ๆ


2
ฉันเห็นด้วยอย่างสมบูรณ์ แต่ฉันได้รับการผลักดันกลับจากคนที่อยู่ในอุตสาหกรรมมักจะเห็นด้วย: พวกเขารู้ว่าพวกเขามีรูปแบบผู้เยี่ยมชมพวกเขาได้เห็นและใช้มันหลายครั้งดังนั้นรหัสในสิ่งนั้นคือสิ่งที่พวกเขาเข้าใจและคุ้นเคย วิธีอื่น ๆ ที่น่าขันกว่าและเรียบง่ายกว่านั้นเป็นเรื่องแปลกสำหรับพวกเขา นี่เป็นความจริงที่โชคร้ายของอุตสาหกรรมที่มี OOP 15 ปีขึ้นไปกระแทกกับหัวหน้าโปรแกรมเมอร์ทุกคนที่โค้ด 100+ บรรทัดนั้นง่ายต่อการเข้าใจมากกว่า 10 เพียงเพราะพวกเขาจำได้ว่า 100+ บรรทัดหลังจากทำซ้ำพวกมันมานานกว่าทศวรรษ
Jimmy Hoffa

1
-1 - รหัสตัวย่อเพิ่มเติมไม่ได้หมายความว่าคุณกำลังเขียนรหัส "น้อยลง" คุณกำลังเขียนรหัสเดียวกันโดยใช้อักขระน้อยลง หากมีสิ่งใดคุณทำผิดพลาดมากขึ้นเนื่องจากรหัสนั้นยากต่อการอ่าน
Telastyn

8
@Telastyn: Terse ไม่เหมือนกับที่อ่านไม่ได้ นอกจากนี้มวลต้มตุ๋นจำนวนมากยังมีวิธีการของตัวเองในการอ่านไม่ได้
Michael Shaw

1
@Telastyn ฉันคิดว่าคุณเพิ่งสัมผัสกับ crux จริงที่นี่ใช่ terse อาจไม่ดีและอ่านไม่ออกป่องอาจไม่ดีและอ่านไม่ได้ด้วย แต่ที่สำคัญไม่ใช่ความยาวของตัวแปรและรหัสที่เขียนด้วยความงง กุญแจสำคัญคือเมื่อคุณกล่าวถึงจำนวนการดำเนินการข้างต้นฉันไม่เห็นด้วยว่าจำนวนการดำเนินการไม่สัมพันธ์กับการบำรุงรักษาฉันคิดว่าการทำสิ่งต่าง ๆ น้อยลง (ด้วยรหัสที่ชัดเจน) จะเป็นประโยชน์ต่อการอ่านและการบำรุงรักษา เห็นได้ชัดว่าการทำหมายเลขเดียวกันของสิ่งที่มีฟังก์ชั่นตัวอักษรเดียวและตัวแปรชื่อจะไม่ช่วยให้ดี FP ต้องการมากการดำเนินงานน้อยยังคงเขียนไว้อย่างชัดเจน
จิมมี่ฮอฟฟา

2
@ user949300: ถ้าคุณต้องการเป็นตัวอย่างที่แตกต่างอย่างสิ้นเชิงวิธีการเกี่ยวกับเรื่องนี้ Java 8 ตัวอย่าง ?: list.forEach(System.out::println);จากจุด FP ในมุมมองของprintlnฟังก์ชั่นการสองข้อโต้แย้งเป้าหมายPrintStreamและคุ้มค่าObjectแต่Collection's forEachวิธีคาดว่าฟังก์ชั่นที่มีเพียงหนึ่งอาร์กิวเมนต์ ซึ่งสามารถนำไปใช้กับทุกองค์ประกอบ ดังนั้นอาร์กิวเมนต์แรกถูกผูกไว้กับอินสแตนซ์ที่พบในการSystem.outยอมฟังก์ชั่นใหม่ที่มีหนึ่งอาร์กิวเมนต์ ง่ายกว่าBiConsumer<…> c=PrintStream::println; PrintStream a1=System.out; list.forEach(a2 -> c.accept(a1, a2));
Holger

5

คุณอาจต้องจำกัดความรู้ในส่วนที่คุณใช้ในที่ทำงานวิธีที่ซูเปอร์แมนต้องแกล้งเป็นคลาร์กเค้นท์เพื่อสนุกกับชีวิตปกติ แต่การรู้มากขึ้นจะไม่ทำให้คุณเจ็บปวด ที่กล่าวไว้บางแง่มุมของการเขียนโปรแกรมฟังก์ชั่นมีความเหมาะสมสำหรับร้านค้า Object Oriented และด้านอื่น ๆ อาจจะคุ้มค่าที่จะพูดคุยกับเจ้านายของคุณเพื่อให้คุณสามารถยกระดับความรู้โดยเฉลี่ยของร้านค้าของคุณและเขียนโค้ดให้ดีขึ้น

FP และ OOP ไม่ได้เกิดขึ้นพร้อมกัน ดู Scala บางคนคิดว่ามันแย่ที่สุดเพราะมันไม่บริสุทธิ์ FP แต่บางคนคิดว่ามันดีที่สุดสำหรับเหตุผลเดียวกัน

นี่คือบางส่วนที่ทำงานได้ดีกับ OOP:

  • ฟังก์ชั่นเพียว (ไม่มีผลข้างเคียง) - ทุกภาษาการเขียนโปรแกรมที่ฉันรู้จักสนับสนุน พวกเขาทำให้รหัสของคุณง่ายขึ้นมากที่จะให้เหตุผลและควรใช้ทุกครั้งที่ใช้งานได้จริง คุณไม่ต้องเรียกมันว่า FP เพียงแค่เรียกว่าการเขียนโปรแกรมที่ดี

  • Immutability: String เป็นวัตถุ Java ที่ใช้กันมากที่สุดและไม่เปลี่ยนรูป ฉันครอบคลุมจาวาออบเจกต์ที่ไม่เปลี่ยนรูปแบบและคอลเลกชัน Java ที่ไม่เปลี่ยนรูปแบบในบล็อกของฉัน บางส่วนอาจมีผลกับคุณ

  • ฟังก์ชั่นชั้นหนึ่ง (ตัวชี้ฟังก์ชั่น / ฟังก์ชั่นวัตถุ / รูปแบบกลยุทธ์) - Java มีรุ่น hobbled ที่กลายพันธุ์ตั้งแต่รุ่น 1.1 กับคลาส API ส่วนใหญ่ (และมีหลายร้อย) ที่ใช้อินเทอร์เฟซผู้ฟัง Runnable น่าจะเป็นวัตถุการทำงานที่ใช้กันมากที่สุด ฟังก์ชั่นเฟิร์สคลาสนั้นทำงานได้มากกว่าการเขียนโค้ดในภาษาที่ไม่รองรับคุณสมบัติดั้งเดิม แต่บางครั้งก็คุ้มค่ากับความพยายามเพิ่มเติมเมื่อพวกมันทำให้ด้านอื่น ๆ ของโค้ดของคุณง่ายขึ้น

  • การเรียกซ้ำมีประโยชน์สำหรับการประมวลผลต้นไม้ ในร้านค้า OOP นั้นน่าจะเป็นการใช้การเรียกซ้ำที่เหมาะสมเป็นหลัก การใช้การเรียกซ้ำเพื่อความสนุกสนานใน OOP อาจเป็นเพราะหากไม่มีเหตุผลอื่นนอกจากภาษา OOP ส่วนใหญ่จะไม่มีพื้นที่สแต็คตามค่าเริ่มต้นเพื่อให้เป็นความคิดที่ดี

  • นิพจน์ (งบเทียบกับ - บรรทัดของรหัสแต่ละผลิตค่าแทนหรือนอกเหนือไปก่อให้เกิดผลข้างเคียง) - ผู้ประกอบการเพียงการประเมินใน C, C ++ และ Java เป็นTernary ผู้ประกอบการ ฉันพูดถึงการใช้งานที่เหมาะสมในบล็อกของฉัน คุณอาจพบว่าคุณเขียนฟังก์ชั่นง่าย ๆ ที่สามารถนำมาใช้ซ้ำได้และประเมินผลได้สูง

  • การประเมิน Lazy (และ Monads) - ส่วนใหญ่เป็นการ จำกัด การเริ่มต้นที่ขี้เกียจใน OOP หากไม่มีคุณสมบัติภาษาที่จะรองรับคุณอาจพบว่า API บางตัวมีประโยชน์ แต่การเขียนของคุณเองนั้นเป็นเรื่องยาก ใช้ประโยชน์สูงสุดจากสตรีมแทน - ดูตัวอย่างอินเทอร์เฟซ Writer และ Reader

  • การใช้งานบางส่วนและการ Currying - ไม่สามารถใช้งานได้หากไม่มีฟังก์ชั่นชั้นหนึ่ง

  • การจับคู่รูปแบบ - ไม่สนับสนุน OOP

โดยสรุปแล้วฉันไม่คิดว่างานควรเป็นของฟรีสำหรับทุกสิ่งที่คุณสามารถทำได้ทุกอย่างที่ภาษาโปรแกรมรองรับจนถึงขีด จำกัด ที่ภาษานั้นรองรับ ฉันคิดว่าผู้ร่วมงานของคุณสามารถอ่านได้ควรเป็นบททดสอบสารสีน้ำเงินสำหรับรหัสที่ทำขึ้นเพื่อการเช่า ที่ไหนที่ร้านกาแฟของคุณจะเป็นจุดเริ่มต้นของการศึกษาเพื่อขยายขอบเขตของเพื่อนร่วมงาน


ตั้งแต่เรียนรู้ FP ฉันคุ้นเคยกับการออกแบบสิ่งต่าง ๆ ให้มีส่วนต่อประสานที่คล่องแคล่วซึ่งส่งผลต่อสิ่งที่คล้ายกับการแสดงออกซึ่งเป็นฟังก์ชั่นที่มีคำสั่งเดียวที่ทำสิ่งต่าง ๆ มากมาย มันใกล้เคียงที่สุดที่คุณจะได้รับจริง ๆ แต่เป็นวิธีการที่ไหลจากความบริสุทธิ์ตามธรรมชาติเมื่อคุณพบว่าคุณไม่มีวิธีที่เป็นโมฆะอีกต่อไปโดยใช้วิธีการขยายแบบคงที่ใน C # ช่วยนี้อย่างมาก ด้วยวิธีการที่จุดแสดงออกของคุณเป็นจุดเดียวที่ฉันไม่เห็นด้วยทุกอย่างอื่นเป็นจุดที่มีประสบการณ์ของฉันเองเรียนรู้ FP และทำงานงานวัน NET.
Jimmy Hoffa

สิ่งที่รบกวนจิตใจฉันใน C # ในขณะนี้คือฉันไม่สามารถใช้ผู้ได้รับมอบหมายแทนการเชื่อมต่อแบบวิธีเดียวด้วยเหตุผลง่ายๆ 2 ข้อ: 1. คุณไม่สามารถสร้าง lambas แบบเรียกซ้ำได้โดยไม่ต้องแฮ็ค (กำหนดให้ null ก่อนจากนั้น combinator (ซึ่งน่าเกลียดเหมือนนรกใน C #) 2. ไม่มีนามแฝงประเภทที่คุณสามารถใช้ในขอบเขตโครงการดังนั้นลายเซ็นของผู้รับมอบสิทธิ์ของคุณจะกลายเป็นไม่สามารถจัดการได้อย่างรวดเร็ว ดังนั้นด้วยเหตุผลโง่ ๆ 2 ข้อนี้ฉันไม่สามารถสนุกกับ C # ได้อีกต่อไปเพราะสิ่งเดียวที่ฉันทำให้มันทำงานได้คือการใช้อินเทอร์เฟซแบบวิธีเดียวซึ่งเป็นงานพิเศษที่ไม่จำเป็น
ตรีศูล D'Gao

@bonomo Java 8 มี java.util.function.BiConsumer ทั่วไปซึ่งอาจเป็นประโยชน์ใน C #: public interface BiConsumer<T, U> { public void accept(T t, U u); }มีอินเตอร์เฟสการทำงานที่มีประโยชน์อื่น ๆ ใน java.util.function
GlenPeterson

@bonomo สวัสดีฉันเข้าใจแล้วนี่คือความเจ็บปวดของ Haskell เมื่อใดก็ตามที่คุณอ่านใครบางคนพูดว่า "การเรียนรู้ FP ทำให้ฉันดีขึ้นที่ OOP" หมายความว่าพวกเขาเรียนรู้ทับทิมหรือบางสิ่งที่ไม่บริสุทธิ์และเปิดเผยเช่น Haskell Haskell ทำให้ OOP ชัดเจนว่าอยู่ในระดับต่ำอย่างไร้ประโยชน์ ความเจ็บปวดที่ใหญ่ที่สุดที่คุณพบคือการอนุมานแบบอิงข้อ จำกัด นั้นไม่สามารถตัดสินใจได้เมื่อคุณไม่ได้อยู่ในระบบ HM ดังนั้นการอนุมานแบบอิง Cosntraint จึงไม่เสร็จสมบูรณ์: blogs.msdn.com/b/ericlippert/archive / 2012/03/09 / …
จิมมี่ฮอฟฟา

1
Most OOP languages don't have the stack space for it จริงๆ? สิ่งที่คุณต้องมีคือระดับการเรียกซ้ำ 30 ระดับเพื่อจัดการโหนดนับพันล้านโหนดในต้นไม้ไบนารีที่สมดุล ฉันค่อนข้างแน่ใจว่าพื้นที่สแต็กของฉันเหมาะสำหรับระดับมากกว่านี้
Robert Harvey

3

นอกเหนือจากการเขียนโปรแกรมการทำงานและการเขียนโปรแกรมเชิงวัตถุแล้วยังมีการเขียนโปรแกรมเชิงประกาศ (SQL, XQuery) การเรียนรู้แต่ละสไตล์ช่วยให้คุณได้รับข้อมูลเชิงลึกใหม่ ๆ และคุณจะได้เรียนรู้การเลือกเครื่องมือที่เหมาะสมสำหรับงาน

แต่ใช่มันอาจเป็นเรื่องน่าหงุดหงิดที่จะเขียนโค้ดในภาษาและรู้ว่าถ้าคุณใช้อย่างอื่นคุณอาจมีประสิทธิผลมากกว่าสำหรับโดเมนที่มีปัญหา อย่างไรก็ตามแม้ว่าคุณจะใช้ภาษาอย่าง Java ก็เป็นไปได้ที่จะนำแนวคิดจาก FP ไปใช้กับโค้ด Java ของคุณแม้ว่าจะเป็นไปในทางอ้อม กรอบ Guava เช่นนี้จะทำบางอย่าง


2

ในฐานะโปรแกรมเมอร์ฉันคิดว่าคุณไม่ควรหยุดเรียนรู้ ที่กล่าวมามันน่าสนใจมากที่การเรียนรู้ FP นั้นทำให้ทักษะ OOP ของคุณเสียไป ฉันมักจะคิดว่าการเรียนรู้ OOP เป็นการเรียนรู้วิธีขี่จักรยาน คุณไม่มีวันลืมวิธีการทำ

เมื่อฉันเรียนรู้เกี่ยวกับการใช้ FP ฉันพบว่าฉันคิดทางคณิตศาสตร์มากขึ้นและได้รับมุมมองที่ดีขึ้นเกี่ยวกับวิธีการที่ฉันเขียนซอฟต์แวร์ นั่นคือประสบการณ์ส่วนตัวของฉัน

ในขณะที่คุณได้รับประสบการณ์มากขึ้นแนวคิดการเขียนโปรแกรมหลักจะยากที่จะสูญเสีย ดังนั้นฉันขอแนะนำให้คุณลองใช้ FP อย่างง่าย ๆ จนกว่าแนวคิด OOP จะถูกทำให้เป็นของแข็งในใจคุณ FP คือการเปลี่ยนกระบวนทัศน์ที่ชัดเจน โชคดี!


4
การเรียนรู้ OOP เปรียบเสมือนการเรียนรู้ที่จะคลาน แต่เมื่อคุณลุกขึ้นยืนอย่างมั่นคงคุณก็จะหันไปคลานเมื่อคุณเมามากเกินไป แน่นอนคุณไม่สามารถลืมวิธีการได้ แต่โดยปกติคุณจะไม่ต้องการ และมันจะเป็นประสบการณ์ที่เจ็บปวดเมื่อต้องเดินไปกับผู้รวบรวมข้อมูลเมื่อคุณรู้ว่าคุณสามารถวิ่งได้
SK-logic

@ SK-logic ฉันชอบ methaphor ของคุณ
Trident D'Gao

@ SK-Logic: การเรียนรู้การเขียนโปรแกรมที่จำเป็นคืออะไร? ลากตัวคุณไปตามท้องของคุณ?
Robert Harvey

@ RobertHarvey พยายามขุดใต้ดินด้วยช้อนสนิมและสำรับพันบัตร
Jimmy Hoffa

0

มีคำตอบที่ดีอยู่แล้วดังนั้นฉันจะตอบคำถามของคุณบางส่วน กล่าวคือฉันรู้สึกไม่มั่นใจกับคำถามของคุณเนื่องจาก OOP และคุณลักษณะการใช้งานนั้นไม่ได้เกิดขึ้นพร้อมกัน

หากคุณใช้ C ++ 11 มีคุณสมบัติการเขียนโปรแกรมฟังก์ชั่นหลายประเภทที่สร้างขึ้นในไลบรารีภาษา / มาตรฐานที่ทำงานร่วมกันได้ดีกับ OOP แน่นอนว่าฉันไม่แน่ใจว่าเจ้านายหรือเพื่อนร่วมงานของคุณจะได้รับ TMP เพียงใด แต่ประเด็นก็คือคุณจะได้รับคุณสมบัติเหล่านี้มากมายในบางรูปแบบหรืออย่างอื่นในภาษาที่ไม่ทำงาน / OOP เช่น C ++

การใช้แม่แบบที่มีการรวบรวมเวลาย้อนกลับอาศัย 3 จุดแรกของคุณ

  • การเปลี่ยนไม่ได้
  • recursion
  • การจับคู่รูปแบบ

ในเทมเพลต - ค่านั้นไม่สามารถเปลี่ยนแปลงได้ (ค่าคงที่เวลาคอมไพล์) การวนซ้ำใด ๆ จะกระทำโดยใช้การเรียกซ้ำและการแยกย่อยจะกระทำโดยใช้การจับคู่รูปแบบ (มากหรือน้อย) ในรูปแบบของการแก้ไขโอเวอร์โหลด

สำหรับประเด็นอื่น ๆ การใช้std::bindและstd::functionให้แอปพลิเคชั่นบางส่วนแก่คุณและพอยน์เตอร์ฟังก์ชั่นนั้นมีอยู่ในภาษา วัตถุที่เรียกใช้ได้เป็นวัตถุที่ใช้งานได้ โปรดทราบว่าด้วยวัตถุ callable operator ()ผมหมายถึงคนที่กำหนดของพวกเขา

การประเมินที่ขี้เกียจและฟังก์ชั่นที่บริสุทธิ์จะยากขึ้นเล็กน้อย สำหรับฟังก์ชั่นที่บริสุทธิ์คุณสามารถใช้ฟังก์ชั่นแลมบ์ดาซึ่งจับตามมูลค่าเท่านั้น แต่ไม่เหมาะ

สุดท้ายนี่คือตัวอย่างของการใช้การเรียกซ้ำเวลาคอมไพล์ด้วยแอปพลิเคชันฟังก์ชันบางส่วน มันเป็นตัวอย่างที่มีการวางแผนมาบ้าง แต่มันแสดงให้เห็นถึงประเด็นข้างต้นส่วนใหญ่ มันจะผูกค่าซ้ำใน tuple ที่กำหนดให้กับฟังก์ชั่นที่กำหนดและสร้างวัตถุฟังก์ชั่น (callable)

#include <iostream>
#include <functional>

//holds a compile-time index sequence
template<std::size_t ... >
struct index_seq
{};

//builds the index_seq<...> struct with the indices (boils down to compile-time indexing)
template<std::size_t N, std::size_t ... Seq>
struct gen_indices
  : gen_indices<N-1, N-1, Seq ... >
{};

template<std::size_t ... Seq>
struct gen_indices<0, Seq ... >
{
    typedef index_seq<Seq ... > type;
};


template <typename RType>
struct bind_to_fcn
{
    template <class Fcn, class ... Args>
    std::function<RType()> fcn_bind(Fcn fcn, std::tuple<Args...> params)
    {
        return bindFunc(typename gen_indices<sizeof...(Args)>::type(), fcn, params);
    }

    template<std::size_t ... Seq, class Fcn, class ... Args>
    std::function<RType()> bindFunc(index_seq<Seq...>, Fcn fcn, std::tuple<Args...> params)
    {
        return std::bind(fcn, std::get<Seq>(params) ...);
    }
};

//some arbitrary testing function to use
double foo(int x, float y, double z)
{
    return x + y + z;
}

int main(void)
{
    //some tuple of parameters to use in the function call
    std::tuple<int, float, double> t = std::make_tuple(1, 2.04, 0.1);                                                                                                                                                                                                      
    typedef double(*SumFcn)(int,float,double);

    bind_to_fcn<double> binder;
    auto other_fcn_obj = binder.fcn_bind<SumFcn>(foo, t);
    std::cout << other_fcn_obj() << std::endl;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.