อะไรทำให้เกิดความนิยมของฟังก์ชั่นแลมบ์ดาในภาษาโปรแกรมกระแสหลักที่ทันสมัย?


112

ในไม่กี่ปีที่ผ่านมาฟังก์ชั่นนิรนาม (ฟังก์ชั่น AKA แลมบ์ดา) ได้กลายเป็นภาษาที่ได้รับความนิยมอย่างมากและเกือบทุกภาษาหลัก / การเขียนโปรแกรมหลักได้แนะนำพวกเขาหรือมีการวางแผนที่จะแนะนำพวกเขาในการแก้ไขมาตรฐาน

แต่ฟังก์ชั่นนิรนามเป็นแนวคิดที่เก่าแก่และเป็นที่รู้จักมากในด้านคณิตศาสตร์และวิทยาการคอมพิวเตอร์ (คิดค้นโดยนักคณิตศาสตร์ Alonzo Church รอบปี 1936 และใช้โดยภาษาการเขียนโปรแกรม Lisp มาตั้งแต่ปี 1958 ดูที่นี่ )

เหตุใดจึงไม่มีภาษาโปรแกรมหลักในปัจจุบัน (หลายภาษาซึ่งมีต้นกำเนิดเมื่อ 15 ถึง 20 ปีก่อน) รองรับฟังก์ชั่นแลมบ์ดาตั้งแต่เริ่มแรกและนำมาใช้ภายหลังเท่านั้น

และสิ่งที่กระตุ้นให้เกิดการยอมรับฟังก์ชั่นที่ไม่ระบุชื่อขนาดใหญ่ในไม่กี่ปีที่ผ่านมา? มีเหตุการณ์เฉพาะความต้องการใหม่หรือเทคนิคการเขียนโปรแกรมที่เริ่มปรากฏการณ์นี้หรือไม่?

โน๊ตสำคัญ

จุดเน้นของคำถามนี้คือการแนะนำฟังก์ชั่นที่ไม่ระบุชื่อในภาษาสมัยใหม่กระแสหลัก (และอาจมีข้อยกเว้นเล็กน้อยภาษาที่ไม่สามารถใช้งานได้) นอกจากนี้โปรดทราบว่าฟังก์ชั่นที่ไม่ระบุชื่อ (บล็อก) มีอยู่ใน Smalltalk ซึ่งไม่ใช่ภาษาที่ใช้งานได้และฟังก์ชั่นที่มีชื่อปกตินั้นมีอยู่ในภาษาขั้นตอนเช่น C และ Pascal เป็นเวลานาน

โปรดอย่าทำให้คำตอบของคุณมากเกินไปโดยการพูดถึง "การยอมรับกระบวนทัศน์การทำงานและประโยชน์ของมัน" เพราะนี่ไม่ใช่หัวข้อของคำถาม


7
15-20 ปีที่แล้วผู้คนถามคำถามเดียวกันเกี่ยวกับ OO ... มันไม่ใช่แนวคิดใหม่ แต่มีการระเบิดของความนิยม
MattDavey

7
@MattDavey ส่วนใหญ่จะไม่เห็นด้วยอย่างแน่นอน แต่จากนั้นฉันต้องเตือนพวกเขาว่า "นักพัฒนา Smalltalk ส่วนใหญ่" ไม่ใช่คนจำนวนมากจริงๆ P
yannis

30
ฉันคิดว่าคำถามที่น่าสนใจยิ่งกว่านั้นคือสิ่งที่กระตุ้นให้เกิดการตายของพวกเขา! หลังจากที่ทุกคนมีเวลาเมื่อภาษาที่ทันสมัยที่สุดได้มี lambdas แล้วภาษาเช่น Java และ C ++ กลายเป็นที่นิยม (แม้ว่าฉันจะไม่เรียกภาษา Java ว่า "ทันสมัย" จริง ๆ แนวคิดที่ทันสมัยที่สุดใน Java คือ Generics ซึ่งย้อนกลับไปในช่วงปลายยุค 60s / ต้นยุค 70 แม้กระทั่งการรวมกันของคุณสมบัติต่างๆของ Java ที่ให้ความปลอดภัยของตัวชี้ความปลอดภัยของหน่วยความจำ ความปลอดภัย, GC, พิมพ์ OO แบบคงที่, Generics ทั้งหมดมีอยู่ในหอไอเฟลในปี 1985 …และดีกว่ามาก, IMHO.)
Jörg W Mittag

31
ก่อนที่ Java 1.0 จะออกมาในขณะที่มันยังอยู่ในช่วงเริ่มต้นของการออกแบบ แต่ทุกคนก็ชี้ให้เห็นว่า Java ต้องการลูกแกะ นักออกแบบบางคนที่ทำงานกับ Java ได้แก่ Guy Steele (ผู้แสดง Lisp, ผู้ออกแบบร่วมของ Scheme, ผู้เขียนร่วม Common Lisp, ผู้ออกแบบป้อมปราการ), James Gosling (เขียนล่าม Emacs Lisp คนแรกสำหรับพีซี), Gilad Bracha (Smalltalk ผู้ร่วมออกแบบของ Animorphic Smalltalk, ผู้ออกแบบ Newspeak), Phil Wadler (ผู้ออกแบบร่วมของ Haskell), Martin Odersky (ผู้ออกแบบ Scala) Java จบลงอย่างไรโดยไม่มีลูกแกะอยู่เหนือฉันจริงๆ
Jörg W Mittag

8
"นิด ๆ หน่อย ๆ " มักจะหมายถึงฟังก์ชั่น 50% เสียง 50%
วินไคลน์

คำตอบ:


86

มีแนวโน้มที่เห็นได้ชัดเจนต่อการเขียนโปรแกรมการทำงานหรืออย่างน้อยก็บางแง่มุมของมัน ภาษายอดนิยมบางภาษาที่บางฟังก์ชั่นใช้งานแบบไม่ระบุชื่อคือ C ++ ( C ++ 11 ), PHP ( PHP 5.3.0 ), C # ( C # v2.0 ), Delphi (ตั้งแต่ปี 2009), Objective C ( บล็อก ) ในขณะที่Java 8 จะนำมาซึ่งการสนับสนุนสำหรับ lambdas ภาษา และมีภาษายอดนิยมที่โดยทั่วไปไม่ได้รับการพิจารณาว่าใช้งานได้ แต่รองรับฟังก์ชั่นนิรนามตั้งแต่เริ่มต้นหรืออย่างน้อยก็ในช่วงต้นเป็นต้น

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

นอกเหนือจากการใช้แนวคิดการทำงานจากภาษาที่ใช้งานได้หลากหลายแล้วยังมีการเปลี่ยนไปใช้ภาษาที่ใช้งานได้ ภาษาเช่น Erlang (1986), Haskell (1990), OCaml (1996), Scala (2003), F # (2005), Clojure (2007) และแม้แต่ภาษาเฉพาะโดเมนเช่น R (1993) ดูเหมือนว่าจะได้รับการติดตามอย่างเข้มแข็ง หลังจากที่พวกเขาได้รับการแนะนำ แนวโน้มทั่วไปได้นำความสนใจใหม่มาสู่ภาษาที่ใช้งานได้มากกว่าเช่น Scheme (1975) และ Common Lisp

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

Joel Spolsky ได้เขียนโพสต์บล็อกที่น่าสนใจอย่างมากคือThe Perils of JavaSchoolsซึ่งเขาโต้แย้งกับแนวโน้มของมหาวิทยาลัยในการสนับสนุน Java มากกว่าภาษาอื่นอาจจะยากที่จะเรียนรู้ภาษา แม้ว่าการโพสต์บล็อกนั้นมีส่วนเกี่ยวข้องกับการเขียนโปรแกรมการทำงานเพียงเล็กน้อย แต่ก็ระบุถึงปัญหาสำคัญ:

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

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

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

คำถามที่เกี่ยวข้อง:

อ่านเพิ่มเติม:


ขอบคุณสำหรับคำตอบ (และแนวคิดที่น่าสนใจมากมาย) +1 แต่ฉันจะเถียงว่าการแนะนำลูกแกะ (เฉพาะ) ในภาษาการเขียนโปรแกรมเป็นขั้นตอนที่เล็กมากต่อ FP และอาจทำให้เกิดความสับสนกับหลาย ๆ คน (ลูกแกะกำลังทำอะไรอยู่คนเดียวในภาษาที่จำเป็น) หลังจากเรียนรู้ Haskell, Scala และ SML ฉันไม่รู้สึกว่าฉันสามารถทำ FP จริงด้วยภาษาที่จำเป็นซึ่งรองรับเฉพาะ lambdas เท่านั้น (สิ่งที่เกี่ยวกับการแกงและการจับคู่รูปแบบ
Giorgio


2
@YannisRizos: Perl มีฟังก์ชั่นที่ไม่ระบุตัวตนตั้งแต่เปิดตัว 5 (1994) ครั้งแรก แต่พวกเขาก็ไม่ได้ "ถูกต้อง" จนกระทั่งถึง 5.004 (1997)
Blrfl

1
@penartur นั่นคือสิ่งที่ฉันคิดเช่นกัน แต่บรรณาธิการที่เป็นมิตรแก้ไขฉันด้วยการชี้ฉันที่นี่: msdn.microsoft.com/en-us/library/0yw3tz5k%28v=vs.80%29.aspx
yannis

ฉันคิดว่าบางที "เหตุการณ์" หลักที่ทำให้เกิดความนิยมในภาษาที่ใช้งานได้คือเว็บ โดยเฉพาะอย่างยิ่งการเปลี่ยนจากโปรแกรมเดสก์ท็อปไปเป็นฝั่งเซิร์ฟเวอร์ สิ่งนี้ให้อิสระกับนักพัฒนาในการเลือกภาษาการเขียนโปรแกรมใด ๆ Paul Graham และ Lisp ในยุค 90 เป็นตัวอย่างที่น่าทึ่ง
Gilad Naor

32

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

ฉันสงสัยว่าภาษา / คุณสมบัติการใช้งานที่ได้รับความนิยมจะเป็นเช่นไรหากไม่ใช่จาวาสคริปต์ที่เพิ่มขึ้นอย่างฉับพลัน


5
Javascript นั้นเป็นภาษาที่สำคัญอย่างแน่นอน แต่ฉันไม่แน่ใจว่าการแนะนำ Javascript นั้นสามารถอธิบายถึงความนิยมของการเขียนโปรแกรมเชิงฟังก์ชันได้หรือไม่: ภาษาการเขียนโปรแกรมการทำงานอื่น ๆ จำนวนมากปรากฏขึ้นในช่วงหลายปีที่ผ่านมา .
Giorgio

8
@Giorgio - อาจมีภาษาการเขียนโปรแกรมการทำงานอื่น ๆ มากมาย แต่ไม่มีใครใช้พวกเขา การใช้ JS และมุมมองที่เพิ่มขึ้นว่าวิธีการทำ C ++ / Java นั้นเป็นสิ่งที่เจ็บปวดและน่ารำคาญจริงๆแล้วเป็นแรงผลักดันสู่กระแสหลักแม้ว่าภาษาเชิงวิชาการจะช่วยยืนยันว่าควรนำไปปฏิบัติอย่างไร
Telastyn

1
ความนิยมของภาษาพลวัตโดยทั่วไปได้รับการพูดถึงในฐานะหนึ่งคำอธิบายสำหรับความนิยมของ Haskell: book.realworldhaskell.org/read/…
yannis

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

@giorgio - พวกเขามีปัญหามากขึ้นในการใช้งานซึ่งแตกต่างจากฟังก์ชั่นสไตล์จาวา รวมเข้ากับการขาดความรู้ / การยอมรับและเป็นตัวเลือกการออกแบบที่ชัดเจน
Telastyn

27

ตัวจัดการเหตุการณ์ JavaScript และ DOM นั้นหมายความว่าโปรแกรมเมอร์นับล้านต้องเรียนรู้อย่างน้อยเกี่ยวกับฟังก์ชั่นชั้นหนึ่งเพื่อที่จะทำการโต้ตอบใด ๆบนเว็บ

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

เมื่อคุณพอใจกับมันแล้วคุณต้องการมันในทุกภาษาที่คุณใช้


7
+1 ไม่ใช่แค่ฟังก์ชั่นนิรนาม การปิดเป็นแนวคิดที่กว้างกว่าการนิยามฟังก์ชั่นชั่วคราวแบบอินไลน์
phkahler

@phkahler: คุณพูดถูกและในแง่นี้แล้ว Java มีการปิด (และมีประสิทธิภาพมากกว่าสิ่งที่คุณได้รับจากฟังก์ชั่นตามตัวอักษร) แต่มันไม่มีสัญกรณ์ที่รัดกุมสำหรับกรณีทั่วไปของคลาสแบบไม่ระบุชื่อแบบวิธีเดียว
Giorgio

17

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

Ruby ไม่ได้เป็นภาษาที่ใช้งานได้และ lambdas, prods, และ blocks ดูเหมือนว่าจะดูรกเมื่อคุณใช้บางอย่างเช่น ML แต่ที่จริงแล้วมันเป็นที่นิยมของแนวคิดเรื่องการทำแผนที่และลดการสร้างโปรแกรมเมอร์รุ่นใหม่ ทุ่งหญ้า แลมบ์ดาในหลายภาษาดูเหมือนจะเป็นการป้องกันมากกว่าสิ่งอื่นใด ("ติดอยู่รอบ ๆ ! เรามีสิ่งเหล่านั้นด้วย !!)

แต่ไวยากรณ์ของบล็อกและวิธีที่รวมเข้ากับ. each, .map, .reduce และอื่น ๆ ทำให้เกิดแนวคิดของฟังก์ชันที่ไม่ระบุชื่อแม้ว่ามันจะเป็นโครงสร้างทางไวยากรณ์ที่ทำตัวเหมือน coroutine และง่ายต่อการแปลงเป็น proc ผ่านทางและทำให้เป็นเกตเวย์ยาสำหรับการเขียนโปรแกรมการทำงาน

ฉันยืนยันว่าโปรแกรมเมอร์ Ruby on Rails ที่เขียน JavaScript ถูกเปิดใช้งานแล้วในการทำสิ่งต่างๆในรูปแบบการทำงานที่มีน้ำหนักเบา จับคู่กับการเขียนบล็อกโปรแกรมเมอร์การประดิษฐ์ Reddit แฮ็กเกอร์ข่าวและการโอเวอร์โฟลว์ในเวลาเดียวกันและความคิดแพร่กระจายเร็วกว่าอินเทอร์เน็ตมากกว่าที่เคยทำในกลุ่มข่าว

TL; DR: Ruby, Rails, JavaScript, บล็อกและ Reddit / Hacker News / Stack Overflow ผลักดันแนวคิดการทำงานให้กับตลาดจำนวนมากดังนั้นทุกคนต้องการให้พวกเขามีภาษาที่มีอยู่เพื่อป้องกันการละเลย


2
+1 สำหรับคำตอบที่ดีและ (ถ้าทำได้เพราะฉันมีหนึ่ง upvote เท่านั้น) +1 สำหรับชี้ให้เห็นว่า "แลมบ์ดาในหลายภาษาดูเหมือนจะเป็นการป้องกันมากกว่าสิ่งอื่นใด (" ยึดติด! !!) ฉันคิดว่านี่เป็นปัจจัยเช่นกันสำหรับบางภาษาแลมบ์ดาเป็นคุณลักษณะที่ดีที่มีแม้ว่ามันจะเพิ่มพลังในการแสดงออกน้อยมากต่อภาษาโดยรวม จำนวนโปรแกรมเมอร์ดูเหมือนจะคิดว่าการรองรับฟังก์ชั่นที่ไม่ระบุชื่อนั้นเทียบเท่ากับการรองรับการเขียนโปรแกรมฟังก์ชั่นอย่างเต็มที่)
Giorgio

2
ฉันคิดว่านี่เป็นเหตุผลว่าทำไมภาษาส่วนใหญ่จึงใช้งานไวยากรณ์ของบล็อกในช่วงไม่กี่ปีที่ผ่านมา แต่วิธีเดียวที่จะตรวจสอบให้แน่ใจคือถามนักพัฒนาภาษาเกี่ยวกับแรงจูงใจของพวกเขา เราสามารถคาดเดา imo เท่านั้น
SpoBo

สำหรับฉัน Ruby เป็นภาษาแรกที่สร้างบล็อกร็อคและน่าสนใจมากดังนั้น +1 Haskell อาจมีผลเช่นกัน
rogerdpack

13

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

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

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

การเพิ่มฟังก์ชั่นสูงในภาษาเป็นขั้นตอนสำคัญในการทำให้การเขียนโปรแกรมพร้อมกันง่ายขึ้น

ปรับปรุง

ฉันจะเพิ่มตัวอย่างที่มีรายละเอียดเพิ่มเติมสองสามข้อเพื่อแก้ไขปัญหาที่โลกิระบุไว้

พิจารณารหัส C # ต่อไปนี้ซึ่งสำรวจชุดของวิดเจ็ตสร้างรายการราคาใหม่ของวิดเจ็ต

List<float> widgetPrices;
    float salesTax = RetrieveLocalSalesTax();
foreach( Widget w in widgets ) {
    widgetPrices.Add( CalculateWidgetPrice( w, salesTax ) );
}

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

พิจารณาวิธีแก้ปัญหาเมื่อมีการเพิ่มฟังก์ชั่นการสั่งซื้อขั้นสูงใน C #:

var widgetPrices = widgets.Select( w=> CalculateWidgetPrice( w, salesTax ) );

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

แต่แน่นอนว่า Select ไม่ได้ทำงานแบบขนาน นั่นคือสิ่งที่ไม่สามารถเปลี่ยนแปลงได้การใช้งาน Select ไม่ทราบว่าฟังก์ชั่นที่ให้ไว้ (CalculateWidgets ด้านบน) ไม่มีผลข้างเคียง ฟังก์ชั่นสามารถเปลี่ยนสถานะของโปรแกรมนอกมุมมองของ Select และการซิงโครไนซ์ทำลายทุกอย่าง ตัวอย่างเช่นในกรณีนี้มูลค่าของ salesTax อาจมีการเปลี่ยนแปลงข้อผิดพลาด ภาษาที่ใช้งานได้จริงให้ความไม่สามารถเปลี่ยนแปลงได้ดังนั้นฟังก์ชั่น Select (map) สามารถรู้ได้ว่าไม่มีการเปลี่ยนแปลงสถานะ

C # เน้นเรื่องนี้โดยการให้ PLINQ เป็นทางเลือกแทน Linq ที่จะมีลักษณะ:

var widgetPrices = widgets.AsParallel().Select(w => CalculateWidgetPrice( w, salesTax) );

ซึ่งใช้ประโยชน์จากคอร์ทั้งหมดของระบบอย่างเต็มที่โดยไม่ต้องจัดการคอร์เหล่านั้นอย่างชัดเจน


ฉันชี้ไปที่ความปรารถนาในการประมวลผลแบบขนานและแบบพร้อมกันมากขึ้นโดยได้กล่าวถึงในบทความ "A history of Erlang" ACM ที่ฉันกำลังลิงก์ไปในย่อหน้าที่สี่ แต่มันเป็นจุดที่ดีมากและฉันน่าจะขยายตัวได้อีกเล็กน้อย +1 เพราะตอนนี้ฉันไม่จำเป็นต้อง P
yannis

คุณพูดถูกฉันดูไม่ดีพอ ฉันแก้ไขคำพูดของฉัน
เบ็น

โอ้คุณไม่ต้องทำอย่างนั้นจริง ๆ ฉันไม่ได้บ่นเลย)
yannis

4
ไม่มีสิ่งที่คุณอธิบายข้างต้นต้องใช้ lambdas ฟังก์ชั่นเดียวกันนี้สามารถทำได้อย่างง่ายดายด้วยฟังก์ชั่นที่ตั้งชื่อ ที่นี่คุณจะเป็นเพียงการจัดเก็บเอกสารcauseและโดยไม่ต้องอธิบายperceived affect correlationIMO บรรทัดสุดท้ายคือคำถามที่เกี่ยวกับ แต่คุณไม่ได้ตอบ ทำไมมันทำให้การเขียนโปรแกรมพร้อมกันง่ายขึ้น
Martin York

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

9

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

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

หากเนื้อหาของฟังก์ชันที่ประมวลผลองค์ประกอบมีเพียงไม่กี่บรรทัดฉันจะใช้ฟังก์ชันที่ไม่ระบุชื่อเพราะตอนนี้เมื่อคุณกำลังอ่านโค้ดฟังก์ชั่นยังคงไม่เปลี่ยนแปลง แต่ผู้อ่านไม่ต้องข้ามไปมาการใช้งานทั้งหมดคือ อยู่ตรงหน้าเขา

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


1
คำอธิบายที่ดีมาก (+1) โปรแกรมเมอร์เสียงกระเพื่อมได้รับทราบทั้งหมดนี้ตั้งแต่ปี 1958 ;-)
Giorgio

4
@Giorgio: แน่นอน แต่โปรแกรมเมอร์เสียงกระเพื่อมยังมีการซื้อแป้นพิมพ์พิเศษกับเสริมปุ่มเปิด / ปิดวงเล็บ :)
DXM

@DXM: ไม่ใช่แป้นพิมพ์พวกเขาได้รับอุปกรณ์ป้อนข้อมูลเพิ่มเติมที่เป็นชนิดของเปียโนสำหรับเปิดและปิดวงเล็บ ;-)
vartec

@DXM, vartec: เคยทำ Scheme มาก่อนแล้วและฉันพบว่าวงเล็บตกลง รหัส C ++ บางอย่างอาจเป็นความลับได้มากขึ้น (และฉันมีประสบการณ์กับ C ++ มากกว่าด้วย Scheme) :-)
Giorgio

9

มีส่วนร่วมในประวัติศาสตร์ที่ผ่านมาที่นี่เล็กน้อยฉันเชื่อว่าปัจจัยหนึ่งคือการเพิ่มของ generics เพื่อ Java และ. NET ที่นำไปสู่ ​​Func < , > และ abstractions การคำนวณที่พิมพ์อย่างอื่น (Task < >, Async < > ฯลฯ )

ใน. NET โลกเราเพิ่มคุณสมบัติเหล่านี้อย่างแม่นยำเพื่อสนับสนุน FP นั่นเป็นชุดของภาษาที่เกี่ยวข้องกับการเขียนโปรแกรมเชิงหน้าที่โดยเฉพาะอย่างยิ่ง C # 3.0, LINQ, Rx และ F # ความก้าวหน้านั้นส่งผลต่อระบบนิเวศอื่น ๆ ด้วยและยังคงดำเนินต่อไปในปัจจุบันใน C #, F # และ TypeScript

แน่นอนว่ามันช่วยให้ Haskell ทำงานที่ MSR ด้วยเช่นกัน :)

แน่นอนว่ายังมีอิทธิพลอื่น ๆ อีกมากมายเช่นกัน (JS แน่นอน) และขั้นตอนเหล่านี้ได้รับอิทธิพลจากสิ่งอื่น ๆ มากมาย - แต่การเพิ่มชื่อสามัญให้กับภาษาเหล่านี้ช่วยทำลาย OO orthodoxy ในช่วงปลายยุค 90 ในส่วนซอฟต์แวร์โลก ประตูสำหรับ FP

ดอนไซม์

ps F # คือปี 2003 ไม่ใช่ปี 2005 - แม้ว่าเราจะบอกว่ามันไม่ถึง 1.0 จนถึงปี 2005 นอกจากนี้เรายังได้สร้างต้นแบบ Haskell.NET ในปี 2001-02


ยินดีต้อนรับ! ฉันใช้ 2005 สำหรับ F # เนื่องจากเป็นปีที่รายงานไว้ในบทความ Wikipedia ของ F # เป็นปีของการปล่อยเสถียรครั้งแรก คุณต้องการให้ฉันเปลี่ยนเป็นปี 2003 หรือไม่
ยานนิส

4

นี่ไม่ได้หมายความว่าจะเป็นคำตอบที่จริงจัง แต่คำถามนี้ทำให้ฉันนึกถึงการโพสต์ที่ตลกขบขันโดย James Iry - ประวัติโดยย่อที่ไม่สมบูรณ์และไม่ถูกต้องส่วนใหญ่ของภาษาการเขียนโปรแกรมภาษาซึ่งรวมถึงวลีต่อไปนี้:

"แลมบ์ดาถูกผลักไสให้ไปสู่ความสับสนจนกระทั่งญาติชวาทำให้พวกเขาได้รับความนิยมโดยไม่มีพวกเขา"


วลีสีทอง :)
pistache

4

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

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

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


ขอบคุณที่เน้นว่าคำถามนี้ไม่เกี่ยวกับการเขียนโปรแกรมใช้งาน (+1) เพราะ (1) ความคิดเกี่ยวกับบล็อกของรหัสที่ถูกส่งไปเนื่องจากการโต้แย้งยังใช้ในภาษาที่ไม่ทำงานเช่น Smalltalk และ (2) สถานะกลายพันธุ์ จับจากบริบทของคำศัพท์ปิด (เป็นไปได้ในการใช้งานแลมบ์ดาอีกหลายคน) แน่นอนไม่ทำงาน และใช่เมื่อปิดแล้วขั้นตอนในการปิดโดยไม่ระบุตัวตนนั้นสั้น สิ่งที่น่าสนใจคือการปิดยังเป็นที่รู้จักกันดีมาเป็นเวลานานและการเขียนโปรแกรมที่ขับเคลื่อนด้วยเหตุการณ์ได้ถูกนำมาใช้ (เท่าที่ฉันรู้) ตั้งแต่แปดทศวรรษ
Giorgio

แต่อาจเป็นเพียงไม่กี่ปีที่ผ่านมาที่ชัดเจนว่าการปิดสามารถใช้บ่อยกว่าที่คิดไว้ก่อนหน้านี้
จอร์โจ

@Giorgio: ใช่แนวคิดส่วนใหญ่ที่ใช้อยู่ในปัจจุบันนั้นใช้เวลานานมาก ถึงกระนั้นพวกเขาก็ไม่ได้ใช้มันอย่างที่เคยใช้
vartec

1

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

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


4
ฟังก์ชั่นที่ไม่เปิดเผยตัวตนในภาษาหลักสตรีม (เช่น C ++ 11) อนุญาตให้มีสถานะที่ไม่แน่นอน (พวกเขาสามารถจับตัวแปรจากสภาพแวดล้อมที่กำหนดและเปลี่ยนแปลงได้ในระหว่างการดำเนินการ) ดังนั้นฉันคิดว่าการพูดเกี่ยวกับกระบวนทัศน์การทำงานโดยทั่วไปและเกี่ยวกับการเปลี่ยนแปลงไม่ได้โดยเฉพาะอย่างยิ่งนั้นเป็นบิตของขอบเขตของคำถามที่ถูกถาม
Giorgio

มีเพียงอ่านคุณสมบัติหมายเหตุสำหรับ Java 8 หนึ่งในเป้าหมายหลักของโครงการแลมบ์ดาคือการสนับสนุนการทำงานพร้อมกัน และนั่นนำเราไปสู่กลุ่มความแปรปรวนแบบทันทีทันใดซึ่งบรรดาสิ่งที่น่าเกรงขามทั้งหมดเหล่านี้จะถูกเรียกใช้ เมื่อ Java ได้รับแลมบ์ดา (โดยสมมติว่าเป็นจริงในรุ่น 8 ขั้นสุดท้าย) พวกเขาจำเป็นต้องจัดการกับปัญหาที่ไม่เปลี่ยนแปลงโดยค่าเริ่มต้น แต่อย่างใด (มันเป็นการทำลายภาษา จากใน COBOL - ตีบนกองข้อมูล / COPYBOOK)
Roboprog

พูดได้ดี. การย้ายออกจากสถานะที่ไม่แน่นอนทำให้การทำงานพร้อมกันง่ายขึ้นและเทคโนโลยีเช่น cascalog และจุดประกายได้อย่างง่ายดายกระจายการเขียนโปรแกรมการทำงานในกลุ่มของคอมพิวเตอร์ ดูglennengstrand.info/analytics/distributed/functional/…สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับวิธีและสาเหตุ
เกล็น

1

หากอาจเพิ่ม€ 0.02 ของฉันแม้ว่าฉันจะเห็นด้วยกับความสำคัญของ JavaScript แนะนำแนวคิดฉันคิดว่ามากกว่าการเขียนโปรแกรมพร้อมกันฉันจะตำหนิแฟชั่นปัจจุบันของการเขียนโปรแกรมแบบอะซิงโครนัส เมื่อทำการโทรแบบอะซิงก์ (จำเป็นสำหรับหน้าเว็บ) ฟังก์ชั่นนิรนามที่ไม่ซับซ้อนนั้นมีประโยชน์อย่างเห็นได้ชัดที่โปรแกรมเมอร์เว็บทุกคน (เช่นโปรแกรมเมอร์ทุกคน) ต้องทำความคุ้นเคยกับแนวคิดนี้


1

อีกตัวอย่างที่เก่าแก่มากของบางสิ่งบางอย่างที่คล้ายกับฟังก์ชั่นที่ไม่ระบุชื่อ / lambdas คือcall-by-nameใน Algol 60 โปรดทราบว่า call-by-name นั้นใกล้เคียงกับการส่งแมโครเป็นพารามิเตอร์มากกว่าการส่งผ่านฟังก์ชั่นที่แท้จริง เข้าใจผลลัพธ์


0

นี่คือบรรพบุรุษของความรู้ที่ดีที่สุดของฉัน

  • 2005: Javascript ได้นำการเขียนโปรแกรมที่มีลำดับสูงกว่ากลับมาเป็นกระแสหลัก ในห้องสมุดเฉพาะเช่นunderscore.jsและjQuery หนึ่งในคนแรกของห้องสมุดเหล่านี้คือprototype.jsซึ่งถือกำเนิด jquery ประมาณปี Prototype ยึดตามโมดูล Enumerable ของ Ruby ซึ่งทำให้เรา ...
  • 1996: โมดูลที่นับได้ของรูดี้เห็นได้ชัดว่าได้รับแรงบันดาลใจมาจากกรอบการรวบรวมของ Smalltalk ดังที่ได้รับการกล่าวถึงโดย Matz ในการสัมภาษณ์หลายครั้งซึ่งนำเราไปสู่ ​​...
  • 1980: Smalltalk ใช้การเขียนโปรแกรมระดับสูงกว่ามากและจัดเตรียม API การรวบรวมที่ใช้การเขียนโปรแกรมแบบลำดับสูงอย่างหนัก (เช่นคลาส Iterable ของ GNU Smalltalk ) ในรหัสสำนวน Smalltalk คุณจะไม่พบลูปใด ๆ แต่มีเฉพาะการแจกแจงลำดับสูง น่าเสียดายที่เมื่อ Java เมื่อเฟรมเวิร์กการรวบรวมของ Smalltalk ถูกย้ายไปยัง Java ในปี 1998 การแจกแจงการสั่งซื้อที่สูงขึ้นนั้นถูกทิ้งไว้ นั่นคือวิธีที่การเขียนโปรแกรมตามลำดับขั้นสูงนั้นไม่ได้อยู่ในกระแสหลักในอีกสิบปีข้างหน้า! Smalltalk มีบรรพบุรุษมากมาย แต่เกี่ยวข้องกับคำถามของ OP คือ LISP ซึ่งทำให้เรา ...
  • 1958: LISP เห็นได้ชัดว่ามีการเขียนโปรแกรมลำดับสูงกว่าที่แกนกลางของมัน

แน่นอนความผิดพลาดเป็นเชื้อสาย ML ทั้งหมด ML, SML, OCaml, Haskell, F # นั่นต้องนับเป็นบางอย่าง ..
Muhammad Alkarouri

-1

ฟังก์ชั่นที่ไม่ระบุชื่อนั้นดีเพราะการตั้งชื่อสิ่งต่าง ๆ เป็นเรื่องยากและถ้าคุณใช้ฟังก์ชั่นเพียงครั้งเดียวก็ไม่จำเป็นต้องใช้ชื่อ

ฟังก์ชั่นแลมบ์ดาเพิ่งกลายเป็นกระแสหลักเพราะเมื่อไม่นานมานี้ภาษาส่วนใหญ่ไม่รองรับการปิด

ฉันอยากจะแนะนำว่า Javascript ได้ผลักดันกระแสหลักนี้ มันเป็นภาษาสากลที่ไม่มีทางที่จะแสดงความเท่าเทียมและฟังก์ชั่นที่ไม่ระบุชื่อทำให้การใช้โมเดลโทรกลับง่ายขึ้น นอกจากนี้ภาษายอดนิยมเช่น Ruby และ Haskell ก็มีส่วนร่วม


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

ฉันรู้ว่า Python ไม่มีการนำ lambdas มาใช้อย่างดีที่สุด แต่ในแง่ของความนิยมมันน่าจะมีส่วนมากกว่าแฮสเคลล์
มูฮัมหมัด Alkarouri
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.