แลมบ์ดาคืออะไรและทำไมจึงมีประโยชน์ [ปิด]


56

จนถึงตอนนี้ฉันได้ยินเกี่ยวกับ:

  • แลมบ์ดาแคลคูลัส
  • การเขียนโปรแกรมแลมบ์ดา
  • นิพจน์แลมบ์ดา
  • ฟังก์ชั่นแลมบ์ดา

ซึ่งดูเหมือนว่าทั้งหมดจะเกี่ยวข้องกับการเขียนโปรแกรมการทำงาน ...

เห็นได้ชัดว่ามันจะถูกรวมเข้ากับ C ++ 1x ดังนั้นฉันอาจเข้าใจได้ดีขึ้นในตอนนี้:

http://en.wikipedia.org/wiki/C%2B%2B0x#Lambda_functions_and_expressions

ใครบางคนสามารถกำหนดสิ่ง lambdas สิ่งสั้น ๆ และให้ที่มันจะมีประโยชน์?


2
โปรดทราบว่าคำศัพท์ทางประวัติศาสตร์มาจากการต้องการวิธีที่ดีในการพูดคุยเกี่ยวกับฟังก์ชั่นที่แสดงโดยการแสดงออก ฟังก์ชั่นที่แทนด้วย x + 1 จะถูกเขียนแลมบ์ดา x x + 1
kasterma

แลมบ์ดาฟังก์ชั่นกินฟังก์ชั่นอื่นและ / หรือค่าอินพุตสร้างฟังก์ชั่นอื่น สิ่งนี้จะดำเนินต่อไปจนกว่าฟังก์ชันจะสร้างโซลูชัน นอกจากนี้ไข่จระเข้
SD

มันคือกรีกทั้งหมดสำหรับฉัน ฉันคิดว่าฉันจะไปมีไจโรฉันชอบเนื้อแกะ, duh

คำตอบ:


44
  • แลมบ์ดาแคลคูลัส

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

แคลคูลัสแลมบ์ดาในรูปแบบพื้นฐานที่สุดมีสองการดำเนินการ: นามธรรม (การสร้างฟังก์ชั่น (ไม่ระบุชื่อ)) และแอปพลิเคชัน (ใช้ฟังก์ชั่น) Abstraction ดำเนินการโดยใช้โอเปอเรเตอร์ giving โดยให้แลมบ์ดาแคลคูลัสชื่อ

  • นิพจน์แลมบ์ดา
  • ฟังก์ชั่นแลมบ์ดา

ฟังก์ชั่นที่ไม่ระบุชื่อมักจะถูกเรียกว่า "lambdas", "ฟังก์ชั่นแลมบ์ดา" หรือ "การแสดงออกแลมบ์ดา" เพราะที่ผมกล่าวข้างต้นλเป็นสัญลักษณ์ในการสร้างฟังก์ชั่นที่ไม่ระบุชื่อในแคลคูลัสแลมบ์ดา (และคำlambdaที่ใช้ในการสร้างฟังก์ชั่นที่ไม่ระบุชื่อในหลายกระเพื่อม ภาษาที่ใช้ด้วยเหตุผลเดียวกัน)

  • การเขียนโปรแกรมแลมบ์ดา

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


ข้อมูลเพิ่มเติมเกี่ยวกับ lambdas ใน C ++ 0x แรงจูงใจของพวกเขาและวิธีการที่เกี่ยวข้องกับพอยน์เตอร์ฟังก์ชั่น (ส่วนมากนี่อาจเป็นการทำซ้ำสิ่งที่คุณรู้อยู่แล้ว แต่ฉันหวังว่ามันจะช่วยอธิบายแรงจูงใจของ lambdas จากตัวชี้ฟังก์ชั่น):

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

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

เพื่อแก้ปัญหานี้ C ++ ได้แนะนำแนวคิดของ "function objects" หรือ "functors" functor นั้นเป็นวัตถุที่มีoperator()วิธีการ ตอนนี้เราสามารถกำหนดคลาสCompareByIthElementซึ่งรับอาร์กิวเมนต์iเป็นอาร์กิวเมนต์คอนสตรัคเตอร์จากนั้นนำเวกเตอร์สองตัวมาเปรียบเทียบเป็นอาร์กิวเมนต์กับoperator()เมธอด ในการจัดเรียงเวกเตอร์ของเวกเตอร์ด้วยiองค์ประกอบที่สามตอนนี้เราสามารถสร้างCompareByIthElementวัตถุiที่มีอาร์กิวเมนต์แล้วผ่านวัตถุนั้นไปยังฟังก์ชันการเรียงลำดับ

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

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

ตอนนี้เพื่อ lambdas:

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

ดังนั้นเพื่อแก้ไข lambdas นี้ถูกนำเสนอ แลมบ์ดาเป็นวัตถุฟังก์ชันไม่ใช่พอยน์เตอร์ของฟังก์ชัน หากคุณใช้แลมบ์ดาตัวอักษรเช่น[x1, x2](y1,y2){bla}รหัสถูกสร้างขึ้นซึ่งโดยทั่วไปจะทำต่อไปนี้:

  1. กำหนดระดับซึ่งมีตัวแปรสมาชิกสอง (กx1และx2) และoperator()มีการขัดแย้ง ( y1และy2) blaและร่างกาย
  2. สร้างอินสแตนซ์ของคลาสการตั้งค่าตัวแปรสมาชิกx1และx2ค่าของตัวแปรx1และx2อยู่ในขอบเขต

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


ฟังก์ชั่นที่ไม่ระบุชื่อถูกนำมาใช้กับตัวชี้ฟังก์ชั่น? ถ้าไม่ใช่ความแตกต่างคืออะไร?
jokoon

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

ดังนั้นตัวชี้ฟังก์ชั่นจึงไม่สามารถมีแลมบ์ดา ...
jokoon

1
+1 คำอธิบายที่ดีเยี่ยม - ฉันไม่สามารถค้นพบสิ่งนั้นได้
Michael K

2
ฉันอยู่กับ Michael ในเรื่องนี้ มันครอบคลุมมาก +1จากฉัน.
sbi

18

โดยทั่วไปแลมบ์ดาเป็นฟังก์ชั่นที่คุณสร้าง "แบบทันที" ใน C ++ 1x สามารถใช้ปรับปรุงการสนับสนุนสำหรับการเขียนโปรแกรมการทำงาน:

std::for_each( begin, end, [](int i){std::cout << i << '\n';} );

สิ่งนี้จะส่งผลให้รหัสคล้ายกับนี้:

struct some_functor {
  void operator()(int i) {std::cout << i << '\n';}
};

std::for_each( begin, end, some_functor() );

หากคุณต้องการsome_functorเพียงแค่การโทรเดียวstd::for_each()ฟังก์ชั่นแลมบ์ดานั้นมีข้อดีหลายประการ:

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

7

ฟังก์ชั่นแลมบ์ดาเป็นอีกชื่อหนึ่งของฟังก์ชั่นนิรนาม

โดยปกติแล้วคุณใช้สิ่งนี้ในภาษาที่คุณจะต้องใช้ฟังก์ชั่นเพียงครั้งเดียว ตัวอย่างเช่นแทน

def add(a, b)
  return a+b

แล้วส่งผ่านฟังก์ชันนั้นไปยังฟังก์ชันอื่นเช่นนั้น

reduce(add, [5,3,2])

ด้วยแลมบ์ดาคุณก็แค่ทำ

reduce(lambda x, y: a+b, [5,3,2])
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.