STDOUT และสิ่งเจือปน


10

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

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

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

คำตอบ:


6

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

ไม่มีใคร "ต้องการ" พระนั่นเป็นวิธีเดียวที่จะอธิบายสิ่งต่าง ๆ ในความเป็นจริงมันอาจไม่ใช่วิธีที่ดีที่สุด บางรูปแบบของการพิมพ์ผล , ประเภทเอกลักษณ์หรือระบบที่อยู่บนพื้นฐานเต็มตรรกะเชิงเส้นดูเหมือนโน้มน้าวใจมากในทางทฤษฎี แต่ทุกขาออกที่รุนแรงมากขึ้นจากระบบการพิมพ์ที่รู้จักกันดีและมีความซับซ้อนมากขึ้นในการแสดง Monadic IO ที่พบใน Haskell เป็นการประนีประนอมระหว่างการใช้งานและความเรียบง่ายเนื่องจากมันเป็นรูปแบบการเขียนโปรแกรมที่จำเป็นอย่างสมบูรณ์ในลักษณะที่สามารถอยู่ร่วมกับระบบประเภท ML ที่มีอยู่แล้วซึ่งใช้ในภาษาได้

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

มันไม่ได้และเราทำไม่ได้ อินพุทและเอาท์พุทจากโปรแกรมโดยรวมถือได้ว่าเป็นข้อโต้แย้งและผลลัพธ์จากการรักษาโปรแกรมทั้งหมดให้เป็นฟังก์ชั่นบริสุทธิ์ขนาดใหญ่ ตราบใดที่มันพิมพ์สิ่งเดียวกันเพื่อ stdout ถ้าคุณให้อาหารสิ่งเดียวกันจาก stdin มันยังคงเป็นฟังก์ชั่นที่บริสุทธิ์ ในความเป็นจริงก่อนที่จะแนะนำ monadic IO Haskell ใช้ระบบ I / O แบบสตรีมที่ใช้ลำธารสันหลังยาวที่บริสุทธิ์สำหรับอินพุตและเอาต์พุต มันลดลงเพราะเห็นได้ชัดว่าเป็นความเจ็บปวดที่จะใช้ซึ่งอาจทำให้คุณมีความคิดว่าทำไมคุณไม่เคยได้ยินอะไรแบบนี้ :]

หากต้องการให้ประเด็นเป็นไปอย่างราบรื่นให้ลองใช้ภาษาลึกลับที่เรียบง่ายLazy K :

Lazy K เป็นภาษาโปรแกรมการทำงานที่โปร่งใสซึ่งอ้างอิงได้ซึ่งเก็บรวบรวมขยะด้วยระบบ I / O แบบสตรีมที่ใช้งานง่าย

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

( ... )

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

( ... )

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

ฉันสงสัยว่าคุณจะพบภาษาที่ใช้งานได้ดีกว่านั้น!


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

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

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


ท่านที่รักฉันต้องสารภาพฉันสนุกกับคำตอบของคุณในกองใด ๆ แน่นอนคุณควรเขียนหนังสือ Haskell และฉันไม่ได้ล้อเล่น
shabunc

@shabunc: บางครั้งฉันก็สงสัยว่าจำนวนคำตอบทั้งหมดของฉันบน SO นั้นใกล้เคียงกับขนาดหนังสือมากแค่ไหน ...
CA McCann

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

@configurator: สังเกตว่าฉันจะเชื่อมโยงกับภาษาที่เฉพาะเจาะจงสำหรับคนอื่น ๆ แต่หน้าวิกิพีเดียสำหรับตรรกะเชิงเส้น? อนิจจาถ้าฉันมีตัวอย่างฉันจะให้มัน : [ทั้งหมดที่ฉันได้ยินมานั้นเป็นเพียงบางส่วนต้นแบบและระบบทดลองจากการวิจัย CS หากคุณต้องการที่จะเจาะลึกลงไปในที่นี้วัสดุที่เข้าถึงได้ค่อนข้างมากในระบบประเภทเชิงเส้นที่อาจช่วยให้คุณเริ่มต้นได้
CA McCann

3

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

โปรแกรมที่มีความบริสุทธิ์อย่างแท้จริงคือตามคำนิยามกล่องดำที่ปิดสนิทและไม่น่าสนใจ

ภาษาทำงาน Haskell จะดูแลปัญหานี้โดยการแยกผลข้างเคียงเช่นการส่งออกในmonads monad รักษารูปแบบการทำงานของการเขียนโปรแกรมอย่างหมดจดในขณะที่ยังทำให้สามารถสร้างผลลัพธ์ได้


แน่นอนว่าคุณพูดถูก แต่ฉันเข้าใจว่าทำไมความบริสุทธิ์ 100% จึงเป็นยูโทเปีย ฉันถามเป็นเพียงเกี่ยวกับ STDOUT
shabunc

1
STDOUT เป็นผลข้างเคียงเหมือนกัน ภายใน monad จะทำการตรวจสอบข้อผิดพลาดใด ๆ ที่อาจจำเป็น
Robert Harvey

ใช่มันคือสิ่งที่คำถามนี้เกี่ยวกับ - ทำไมมันถือว่าเป็นผลข้างเคียงเช่นเดียวกับคนอื่น ๆ ?
shabunc

2
อะไรก็ตามที่แก้ไขโลกภายนอกถือว่าเป็นผลข้างเคียง
Robert Harvey

1

การเขียนไปที่ STDOUT อาจล้มเหลวหากคุณไม่ได้เชื่อมต่อกับอุปกรณ์ปลายทางหรือหากคุณ (ด้วยเหตุผลบางอย่าง) ให้ปิดไฟล์ตัวอธิบายไฟล์

นอกจากนี้ STDOUT อาจไม่ใช่ "หน้าจอคอนโซล" เสมอ บางครั้งก็ส่งไปยังโปรแกรมอื่น บางครั้งท่อแตก


0

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

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


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