ข้อยกเว้นใน Haskell ทำงานอย่างไร


87

ใน GHCi:

Prelude> error (error "")
*** Exception: 
Prelude> (error . error) ""
*** Exception: *** Exception: 

เหตุใดข้อแรกจึงไม่เป็นข้อยกเว้นที่ซ้อนกัน


9
นี่คือการเปลี่ยนแปลงที่ GHC อนุญาตให้ทำ: "ฉันเป็นคอมไพเลอร์ที่ดำเนินการด้วยตัวเองและ _ | _ ทั้งหมดก็เหมือนกับฉัน" คุณกำลังขอรายละเอียดการใช้งานที่ทำให้ทั้งสองบรรทัดคอมไพล์แตกต่างกันหรือไม่?
shachaf

3
errorเป็นกลไกพิเศษและไม่ใช่กลไกยกเว้น สำหรับข้อยกเว้นที่จับได้จริงโปรดดูErrormonad
Cat Plus Plus

1
ตัวอย่างเช่นหมายเหตุที่(\f g x -> f (g x)) error error ""ทำงานแตกต่างจาก(.) error error ""แม้ว่าฟังก์ชันนั้นจะเทียบเท่ากับ(.). อาจเกี่ยวข้องกับแฟล็กการปรับให้เหมาะสมที่ Prelude ถูกคอมไพล์ด้วย
shachaf

5
นอกจากนี้และน่ากลัวiterate error "" !! n fix error
Vitus

9
ฉันมักจะแสร้งทำเป็นอย่างนั้นerror = errorและตั้งโปรแกรมตามนั้น
Gabriel Gonzalez

คำตอบ:


103

คำตอบคือนี่เป็นความหมายของข้อยกเว้นที่ไม่ชัดเจน (ค่อนข้างน่าแปลกใจ)

เมื่อรหัสบริสุทธิ์สามารถแสดงเพื่อประเมินเป็นชุดของค่าพิเศษ (เช่นค่าของ errorหรือundefinedและอย่างชัดเจนไม่ใช่ชนิดของข้อยกเว้นที่สร้างขึ้นใน IO ) ภาษาจะอนุญาตให้ส่งคืนค่าใด ๆ ของชุดนั้น ค่าพิเศษใน Haskell มีลักษณะคล้ายกับNaNรหัสทศนิยมมากกว่าข้อยกเว้นตามโฟลว์การควบคุมในภาษาที่จำเป็น

gotcha เป็นครั้งคราวสำหรับแม้แต่ Haskellers ขั้นสูงก็เป็นกรณีเช่น:

 case x of
   1 -> error "One"
   _ -> error "Not one"

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

ทำไมเราถึงทำเช่นนี้? เพราะไม่เช่นนั้นเราจะ จำกัด ลำดับการประเมินของภาษามากเกินไปเช่นเราจะต้องแก้ไขผลลัพธ์ที่กำหนดไว้สำหรับ:

 f (error "a") (error "b")

โดยตัวอย่างเช่นกำหนดให้มีการประเมินจากซ้ายไปขวาหากมีค่าความผิดพลาด ฮาสเคลลี่มาก!

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

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


การอ้างอิง: ความหมายสำหรับข้อยกเว้นที่ไม่ชัดเจน Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson Proc Programming Languages ​​Design and Implementation (PLDI'99), Atlanta ( PDF )


2
ฉันเข้าใจว่า GHC เลือกหนึ่งในข้อยกเว้นที่อาจพบได้ แต่ในตัวอย่าง "กรณี" ของคุณไม่สามารถพบข้อยกเว้น "ไม่ใช่หนึ่ง" สำหรับอินพุต 1 ดังนั้นฉันจึงยังคงจัดว่าเป็นข้อบกพร่อง
Peaker

8
@Peaker dead code กำจัด - เครื่องมือเพิ่มประสิทธิภาพไม่จำเป็นต้องดูที่ x เพื่อดูว่ามีข้อผิดพลาดเกิดขึ้นทุกสาขาให้ค่า "เท่ากัน" ดังนั้นจึงสามารถละเว้นค่าอินพุตได้ทั้งหมด ไม่ใช่ข้อผิดพลาดภายใต้ข้อยกเว้นที่ไม่ชัดเจน!
Don Stewart

1
@lpsmith: ฉันคิดว่าข้อยกเว้นทุกประเภทไม่ชัดเจน (เมื่อโยนโดยใช้throw) และคุณสามารถกำหนดข้อยกเว้นthrowIOได้
FunctorSalad

4
@ Peaker ฉันคิดว่าคุณพูดถูก ฉันไม่คิดว่า ghc ควรปรับนิพจน์นี้ให้เหมาะสมหากพวกเขาต้องการเล่นตามกฎที่ระบุไว้ในกระดาษข้อยกเว้นที่ไม่ชัดเจน
09:29 น

3
สิ่งที่ดูเหมือนว่ากระดาษข้อยกเว้นที่ไม่ชัดเจนก็คือถ้ากรณี scrutineeเป็นค่าความผิดพลาดจะสามารถส่งคืนค่าความผิดพลาดจากกิ่งก้านได้ จึงcase error "banana" of (x:xs) -> error "bonobo"สามารถให้คุณ* Exception: bonobo.
Ben Millwood
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.