ภาษาที่ใช้งานได้ไม่อนุญาตให้มีผลข้างเคียงหรือไม่


10

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

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

แต่นอกจากนี้ผลข้างเคียงยังมีคำจำกัดความอื่น ผลข้างเคียง

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

ในแง่นั้นภาษาการเขียนโปรแกรมฟังก์ชั่นจริงอนุญาตให้มีผลข้างเคียงเนื่องจากมีตัวอย่างมากมายของฟังก์ชั่นที่มีผลต่อโลกภายนอกของพวกเขาเรียกฟังก์ชั่นอื่น ๆ ยกข้อยกเว้นการเขียนไฟล์ ฯลฯ

ดังนั้นในที่สุดภาษาการเขียนโปรแกรมฟังก์ชั่นอนุญาตให้มีผลข้างเคียงหรือไม่?

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

คำตอบ:


26

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

หากฟังก์ชันมีผลข้างเคียงนี่อาจไม่ถือ ค่าส่งคืนไม่เท่ากับการเรียกใช้ฟังก์ชันเนื่องจากค่าส่งคืนไม่มีผลข้างเคียง

การแก้ปัญหาคือจะหยุดการใช้ด้านผลกระทบและการเข้ารหัสผลกระทบเหล่านี้ในค่าตอบแทน ภาษาที่ต่างกันมีระบบเอฟเฟกต์ที่แตกต่างกัน เช่น Haskell ใช้ monads เพื่อเข้ารหัสเอฟเฟกต์บางอย่างเช่น IO หรือการกลายพันธุ์ของรัฐ ภาษา C / C ++ / Rust มีระบบประเภทที่สามารถไม่อนุญาตการกลายพันธุ์ของค่าบางค่า

ในภาษาที่จำเป็นprint("foo")ฟังก์ชันจะพิมพ์บางอย่างและไม่คืนสิ่งใด ในภาษาที่ใช้งานได้จริงเช่น Haskell printฟังก์ชั่นยังใช้วัตถุที่แสดงสถานะของโลกภายนอกและส่งคืนวัตถุใหม่ที่เป็นตัวแทนของรัฐหลังจากดำเนินการเอาต์พุตนี้ newState = print "foo" oldStateสิ่งที่คล้ายกับ ฉันสามารถสร้างรัฐใหม่ให้มากที่สุดจากสถานะเดิมได้ตามต้องการ อย่างไรก็ตามฟังก์ชั่นหลักจะใช้เพียงอันเดียวเท่านั้น ดังนั้นฉันต้องเรียงลำดับสถานะจากการกระทำหลาย ๆ อย่างโดยการผูกมัดฟังก์ชัน จะพิมพ์ผมอาจจะพูดอะไรบางอย่างเช่นfoo barprint "bar" (print "foo" originalState)

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

โปรดทราบว่า Haskell เป็นภาษาที่ใช้งานได้ทั่วไปเท่านั้นที่ใช้เส้นทางนี้ ภาษาที่ใช้งานอื่น ๆ รวมถึง ตระกูล Lisp ตระกูล ML และภาษาที่ใช้งานได้ใหม่เช่น Scala ไม่สนับสนุน แต่ให้ผลข้างเคียงที่ยังคงอยู่

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

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


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

3
@ codebot, ไม่มากในความคิดของฉัน หากดำเนินการอย่างเหมาะสมผลข้างเคียงในการตั้งโปรแกรมการทำงานควรสะท้อนให้เห็นในประเภทการคืนค่าของฟังก์ชัน ตัวอย่างเช่นหากฟังก์ชั่นอาจล้มเหลว (หากไฟล์ใดไฟล์หนึ่งไม่มีอยู่หรือไม่สามารถสร้างการเชื่อมต่อฐานข้อมูลได้) ดังนั้นประเภทการส่งคืนของฟังก์ชั่นควรจะแค็ปซูลความล้มเหลวแทนที่จะทำให้เกิดข้อยกเว้น ลองดูตัวอย่างการเขียนโปรแกรมเชิงรถไฟ ( fsharpforfunandprofit.com/posts/recipe-part2 )
Aaron M. Eshbach

"... พวกเขาอาจเรียกได้ว่าเป็นภาษาที่ใช้งานได้ดี": Simon Peyton Jones เขียนว่า "... Haskell เป็นภาษาการเขียนโปรแกรมที่จำเป็นที่สุดในโลก"
Giorgio

5

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

ฉันคิดว่ามันช่วยในการอธิบายความแตกต่างด้วยตัวอย่าง

a = b + c

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

ในภาษาที่จำเป็น (C, Java, Javascript, & c.) บรรทัดของโค้ดนั้นแสดงถึงขั้นตอนในกระบวนการ มันไม่ได้บอกอะไรเราเกี่ยวกับธรรมชาติพื้นฐานของค่าใด ๆ มันบอกเราว่าในเวลาต่อมาหลังจากบรรทัดของโค้ดนี้ (แต่ก่อนหน้าบรรทัดถัดไป) aจะเท่ากันbบวกcแต่มันไม่ได้บอกอะไรเราaในแง่ที่กว้างขึ้น

ในภาษาที่ประกาศได้ (Haskell, Scheme, Excel, & c.) บรรทัดของโค้ดดังกล่าวบอกอีกมากมาย มันกำหนดความสัมพันธ์ระหว่างค่าคงที่aและอีกสองวัตถุดังกล่าวว่าจะเสมอเป็นกรณีที่aมีค่าเท่ากับบวกb cโปรดทราบว่าฉันรวม Excel ไว้ในรายการภาษาที่ประกาศเนื่องจากแม้ว่าbหรือcเปลี่ยนแปลงค่าความจริงก็ยังคงอยู่ซึ่งaจะเท่ากับผลรวมของพวกเขา

ในใจของฉันสิ่งนี้ไม่ใช่ผลข้างเคียงหรือสภาวะเป็นสิ่งที่ทำให้ภาษาทั้งสองประเภทแตกต่างกัน ในภาษาที่จำเป็นบรรทัดของรหัสใด ๆ จะบอกอะไรคุณเกี่ยวกับความหมายโดยรวมของตัวแปรที่เป็นปัญหา ในคำอื่น ๆa = b + cหมายถึงเฉพาะว่าเป็นช่วงเวลาที่สั้นมากในเวลาที่aเกิดขึ้นให้เท่ากับผลรวมของและbc

ในภาษาที่ประกาศทุกบรรทัดของรหัสสร้างความจริงพื้นฐานที่จะมีอยู่ตลอดชีวิตของโปรแกรม ในภาษาเหล่านี้a = b + cจะบอกคุณว่าไม่ว่าสิ่งที่เกิดขึ้นในสายอื่น ๆ ของรหัสไม่มีaเสมอจะเท่ากับผลรวมของและbc

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