เข้าใจความแตกต่างระหว่างขั้นตอนและการทำงานอย่างแท้จริง


114

ฉันมีช่วงเวลาที่ยากลำบากในการทำความเข้าใจความแตกต่างระหว่างกระบวนทัศน์การเขียนโปรแกรมขั้นตอนและฟังก์ชัน

นี่คือสองย่อหน้าแรกจากรายการ Wikipedia เกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชัน :

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

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

ในวรรค 2 ที่ระบุว่า

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

นั่นไม่ใช่กรณีเดียวกันสำหรับการเขียนโปรแกรมขั้นตอนหรือไม่?

เราควรมองหาอะไรในขั้นตอนและฟังก์ชันที่โดดเด่น?


1
ลิงก์ "Charming Python: Functional Programming in Python" จาก Abafei เสีย ลิงค์ที่ดีมีดังนี้ibm.com/developerworks/linux/library/l-prog/index.html ibm.com/developerworks/linux/library/l-prog2/index.html
Chris Koknat

อีกประการหนึ่งคือการตั้งชื่อ เช่น. ใน JavaScript และ Common Lisp เราใช้ฟังก์ชันคำศัพท์แม้ว่าจะได้รับอนุญาตให้ใช้ผลข้างเคียงและใน Scheme ก็เรียกว่าขั้นตอนเช่นเดียวกัน ฟังก์ชัน CL ที่บริสุทธิ์สามารถเขียนเป็นขั้นตอนของ Scheme ที่ใช้งานได้จริง หนังสือเกือบทุกเล่มเกี่ยวกับ Scheme ใช้คำว่า Procedure เนื่องจากเป็น Tyerm ที่ใช้ในมาตรฐานและไม่มีส่วนเกี่ยวข้องกับการเป็นขั้นตอนหรือการทำงาน
Sylwester

คำตอบ:


276

การเขียนโปรแกรมฟังก์ชั่น

การเขียนโปรแกรมเชิงฟังก์ชันหมายถึงความสามารถในการถือว่าฟังก์ชันเป็นค่า

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

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

โปรดทราบว่าหลายภาษามีความสามารถในการเขียนโปรแกรมที่ใช้งานได้ - แม้แต่ภาษาที่มักไม่คิดว่าเป็นภาษาที่ใช้งานได้ แม้แต่ปู่ FORTRAN ก็สนับสนุนค่าฟังก์ชันแม้ว่ามันจะไม่ได้ให้ตัวดำเนินการรวมฟังก์ชันมากนัก สำหรับภาษาที่เรียกว่า "ฟังก์ชัน" จำเป็นต้องยอมรับความสามารถในการเขียนโปรแกรมเชิงฟังก์ชันเป็นหลัก

การเขียนโปรแกรมขั้นตอน

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

ความคมชัด

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

function allOdd(words) {
  var result = true;
  for (var i = 0; i < length(words); ++i) {
    var len = length(words[i]);
    if (!odd(len)) {
      result = false;
      break;
    }
  }
  return result;
}

ผมจะเอาเป็นตัวอย่างว่าตัวอย่างนี้เข้าใจได้ ตอนนี้รูปแบบการใช้งาน:

function allOdd(words) {
  return apply(and, map(compose(odd, length), words));
}

การทำงานจากภายในสู่ภายนอกคำจำกัดความนี้ทำสิ่งต่อไปนี้:

  1. compose(odd, length)รวมฟังก์ชันoddและlengthเพื่อสร้างฟังก์ชันใหม่ที่กำหนดว่าความยาวของสตริงเป็นเลขคี่หรือไม่
  2. map(..., words)เรียกฟังก์ชันใหม่นั้นสำหรับแต่ละองค์ประกอบในwordsท้ายที่สุดจะส่งคืนรายการค่าบูลีนใหม่โดยแต่ละรายการระบุว่าคำที่เกี่ยวข้องมีอักขระจำนวนคี่หรือไม่
  3. apply(and, ...)ใช้ตัวดำเนินการ "และ" กับรายการผลลัพธ์และ -ing บูลีนทั้งหมดเข้าด้วยกันเพื่อให้ได้ผลลัพธ์สุดท้าย

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

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

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

คำถามนี้เกิดขึ้นมากมาย ... ดูตัวอย่าง:

การบรรยายที่ได้รับรางวัล Turing ของ John Backus บ่งบอกถึงแรงจูงใจในการเขียนโปรแกรมเชิงฟังก์ชันโดยละเอียด:

การเขียนโปรแกรมสามารถปลดปล่อยจากสไตล์ฟอนนอยมันน์ได้หรือไม่?

ฉันไม่ควรพูดถึงบทความนั้นในบริบทปัจจุบันเพราะมันค่อนข้างมีเทคนิคค่อนข้างเร็ว ฉันไม่สามารถต้านทานได้เพราะฉันคิดว่ามันเป็นพื้นฐานที่แท้จริง


ภาคผนวก - 2556

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

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

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

ตัวอย่างที่จัดแสดงนั้นจงใจหลีกเลี่ยงการผสมผสานในรูปแบบการเขียนโปรแกรมอื่น ๆ เหล่านี้เพื่อเน้นความแตกต่างระหว่างสองสไตล์ภายใต้การสนทนา


1
คำตอบที่ดีจริง ๆ แต่คุณช่วยลดความซับซ้อนของโค้ดได้เล็กน้อยเช่น: "function allOdd (words) {foreach (auto word in words) {odd (length (word)? return false:;} return true;}"
Dainius

รูปแบบการใช้งานค่อนข้างอ่านยากเมื่อเทียบกับ "รูปแบบการทำงาน" ใน python: def odd_words (คำ): return [x สำหรับ x ในคำถ้าคี่ (len (x))]
บรรจุกล่องใน

@boxed: คุณนิยามทำบางสิ่งที่แตกต่างจากคำตอบของodd_words(words) allOddสำหรับการกรองและการทำแผนที่มักต้องการความเข้าใจในรายการ แต่ในที่นี้ฟังก์ชั่นallOddควรจะลดรายการคำให้เป็นค่าบูลีนเดียว
ShinNoNoir

@WReach: ฉันได้เขียนตัวอย่างการทำงานของคุณเช่นนี้: function allOdd (คำ) {return and (odd (length (first (words))), allOdd (rest (words))); } มันไม่ได้สวยหรูไปกว่าตัวอย่างของคุณ แต่ในภาษาหางซ้ำมันจะมีลักษณะการทำงานเช่นเดียวกับรูปแบบที่จำเป็น
mishoo

@mishoo ภาษาจะต้องมีทั้งการวนซ้ำและเข้มงวดและการลัดวงจรในตัวดำเนินการและเพื่อให้สมมติฐานของคุณถือฉันเชื่อ
kqr

46

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

จากผลของความคิดนี้โดยทั่วไปโปรแกรม FP จะอธิบายถึงสิ่งที่จะเกิดขึ้นแทนที่จะเป็นกลไกเฉพาะว่ามันจะเกิดขึ้นได้อย่างไรซึ่งมีประสิทธิภาพมากเพราะถ้าเราสามารถระบุได้อย่างชัดเจนว่า "Select" และ "Where" และ "Aggregate" หมายถึงอะไรเรา มีอิสระที่จะเปลี่ยนการใช้งานของพวกเขาเช่นเดียวกับที่เราทำกับ AsParallel () และทันใดนั้นแอปเธรดเดียวของเราก็ขยายขนาดเป็นnคอร์


วิธีใดที่คุณสามารถเปรียบเทียบทั้งสองโดยใช้ตัวอย่างโค้ด? ซาบซึ้งจริงๆ
Philoxopher

1
@KerxPhilo: นี่เป็นงานที่ง่ายมาก (เพิ่มตัวเลขจาก 1 ถึง n) จำเป็น: แก้ไขหมายเลขปัจจุบันแก้ไขผลรวมจนถึงปัจจุบัน รหัส: int i, sum; ผลรวม = 0; สำหรับ (i = 1; i <= n; i ++) {sum + = i; } ฟังก์ชั่น (Haskell): จดรายการตัวเลขที่ขี้เกียจพับเข้าด้วยกันในขณะที่บวกเป็นศูนย์ รหัส: foldl (+) 0 [1..n]. ขออภัยไม่มีการจัดรูปแบบในความคิดเห็น
dirkt

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

12
     Isn't that the same exact case for procedural programming?

ไม่ได้เนื่องจากรหัสขั้นตอนอาจมีผลข้างเคียง ตัวอย่างเช่นสามารถจัดเก็บสถานะระหว่างการโทร

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


1
คุณสามารถแสดงตัวอย่างและเปรียบเทียบได้หรือไม่? ขอบคุณอย่างแท้จริงถ้าคุณทำได้
Philoxopher

8
ฟังก์ชัน Rand () ใน C ให้ผลลัพธ์ที่แตกต่างกันสำหรับทุกการโทร มันเก็บสถานะระหว่างการโทร ไม่โปร่งใสโดยอ้างอิง ในการเปรียบเทียบ std :: max (a, b) ใน C ++ จะส่งคืนผลลัพธ์เดียวกันเสมอโดยมีอาร์กิวเมนต์เดียวกันและไม่มีผลข้างเคียง (ที่ฉันรู้จัก ... )
Andy Thomas

11

ฉันไม่เห็นด้วยกับคำตอบของ WReach ลองแยกแยะคำตอบของเขาสักหน่อยเพื่อดูว่าความขัดแย้งนั้นมาจากไหน

ประการแรกรหัสของเขา:

function allOdd(words) {
  var result = true;
  for (var i = 0; i < length(words); ++i) {
    var len = length(words[i]);
    if (!odd(len)) {
      result = false;
      break;
    }
  }
  return result;
}

และ

function allOdd(words) {
  return apply(and, map(compose(odd, length), words));
}

สิ่งแรกที่ควรทราบคือเขากำลังประชุมกัน:

  • การทำงาน
  • เน้นการแสดงออกและ
  • Iterator เป็นศูนย์กลาง

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

เรามาพูดถึงสิ่งเหล่านี้อย่างรวดเร็ว

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

lengths: map words length
each_odd: map lengths odd
all_odd: reduce each_odd and

สิ่งนี้ค่อนข้างเหมือนกับที่ให้มาก่อนหน้านี้ยกเว้นฟังก์ชั่นจะถูกผูกมัดอย่างหมดจดผ่านโซ่ของข้อความและการผูก

Python สามารถใช้รูปแบบการเขียนโปรแกรม iterator เป็นศูนย์กลางได้ ลองใช้อย่างหมดจดซ้ำสไตล์ iterator เป็นศูนย์กลาง:

def all_odd(words):
    lengths = (len(word) for word in words)
    each_odd = (odd(length) for length in lengths)
    return all(each_odd)

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

แน่นอนคุณสามารถบีบอัดสิ่งนี้:

def all_odd(words):
    return all(odd(len(word)) for word in words)

ความจำเป็นไม่ได้ดูแย่ขนาดนี้ใช่มั้ย? :)

ประเด็นสุดท้ายเกี่ยวกับขั้นตอนการควบคุมที่ชัดเจนมากขึ้น มาเขียนโค้ดเดิมใหม่เพื่อใช้ประโยชน์จากสิ่งนี้:

function allOdd(words) {
    for (var i = 0; i < length(words); ++i) {
        if (!odd(length(words[i]))) {
            return false;
        }
    }
    return true;
}

การใช้ตัวทำซ้ำคุณสามารถมี:

function allOdd(words) {
    for (word : words) { if (!odd(length(word))) { return false; } }
    return true;
}

ดังนั้นสิ่งที่เป็นจุดภาษาทำงานถ้าแตกต่างระหว่าง:

return all(odd(len(word)) for word in words)
return apply(and, map(compose(odd, length), words))
for (word : words) { if (!odd(length(word))) { return false; } }
return true;


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

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

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

all = partial(apply, and)

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


คุณรู้ไหมฉันค่อนข้างแน่ใจว่าการapplyดำเนินการไม่เหมือนกับ a foldหรือreduceแม้ว่าฉันจะเห็นด้วยกับความสามารถที่ดีในการมีอัลกอริทึมทั่วไป
Benedict Lee

ฉันไม่เคยได้ยินapplyว่าหมายถึงfoldหรือreduceแต่สำหรับฉันแล้วดูเหมือนว่ามันจะต้องอยู่ในบริบทนี้เพื่อให้มันส่งคืนบูลีน
Veedrac

อ่าตกลงฉันสับสนกับการตั้งชื่อ ขอขอบคุณที่ทำให้ข้อมูลชัดเจนขึ้น
Benedict Lee

6

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

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

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


2

เสน่ห์หลาม: การเขียนโปรแกรมการทำงานในหลามจากIBM developerWorksช่วยจริงๆผมที่จะเข้าใจความแตกต่าง

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


2

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

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


1

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


0

ความแตกต่างที่ชัดเจนอย่างหนึ่งระหว่างกระบวนทัศน์การเขียนโปรแกรมทั้งสองคือสภาวะ

ใน Functional Programming จะหลีกเลี่ยงสถานะ พูดง่ายๆคือจะไม่มีตัวแปรที่กำหนดค่า

ตัวอย่าง:

def double(x):
    return x * 2

def doubleLst(lst):
    return list(map(double, action))

อย่างไรก็ตามการเขียนโปรแกรมขั้นตอนใช้สถานะ

ตัวอย่าง:

def doubleLst(lst):
    for i in range(len(lst)):
        lst[i] = lst[i] * 2  # assigning of value i.e. mutation of state
    return lst
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.