Trong GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Tại sao cái đầu tiên không phải là một ngoại lệ lồng nhau?
Trong GHCi:
Prelude> error (error "")
*** Exception:
Prelude> (error . error) ""
*** Exception: *** Exception:
Tại sao cái đầu tiên không phải là một ngoại lệ lồng nhau?
error
là đặc biệt và không thực sự là một cơ chế ngoại lệ. Đối với các ngoại lệ thực, có thể bắt được xem Error
đơn nguyên.
(\f g x -> f (g x)) error error ""
hoạt động khác với (.) error error ""
, mặc dù chức năng đó tương đương với (.)
. Có lẽ nó liên quan đến các cờ tối ưu hóa mà Prelude đã được biên dịch.
iterate error "" !! n
và tuyệt vời fix error
.
error = error
và lập trình cho phù hợp.
Câu trả lời:
Câu trả lời là đây là ngữ nghĩa (hơi ngạc nhiên) của các ngoại lệ không chính xác
Khi mã thuần túy có thể được hiển thị để đánh giá một tập hợp các giá trị đặc biệt (tức là giá trị của error
hoặc undefined
và rõ ràng không phải là loại ngoại lệ được tạo ra trong IO ), thì ngôn ngữ cho phép trả về bất kỳ giá trị nào của tập hợp đó. Các giá trị ngoại lệ trong Haskell giống NaN
trong mã dấu phẩy động hơn là các ngoại lệ dựa trên luồng điều khiển trong các ngôn ngữ mệnh lệnh.
Một gotcha không thường xuyên cho các Haskellers nâng cao thậm chí là một trường hợp như:
case x of
1 -> error "One"
_ -> error "Not one"
Vì mã đánh giá một tập hợp các trường hợp ngoại lệ, nên GHC có quyền chọn một trường hợp ngoại lệ. Khi bật tối ưu hóa, bạn có thể thấy điều này luôn được đánh giá là "Không phải một".
Tại sao chúng ta làm việc này? Bởi vì nếu không, chúng tôi sẽ quá hạn chế thứ tự đánh giá của ngôn ngữ, ví dụ: chúng tôi sẽ phải sửa một kết quả xác định cho:
f (error "a") (error "b")
chẳng hạn, yêu cầu nó được đánh giá từ trái sang phải nếu có giá trị lỗi. Rất không Haskelly!
Vì chúng tôi không muốn làm tê liệt các tối ưu hóa có thể được thực hiện trên mã của chúng tôi chỉ để hỗ trợ error
, giải pháp là chỉ định rằng kết quả là một lựa chọn không xác định từ tập hợp các giá trị đặc biệt: ngoại lệ không chính xác! Theo một cách nào đó, tất cả các ngoại lệ đều được trả về và một ngoại lệ được chọn.
Thông thường, bạn không quan tâm - một ngoại lệ là một ngoại lệ - trừ khi bạn quan tâm đến chuỗi bên trong ngoại lệ, trong trường hợp đó, việc sử dụng error
để gỡ lỗi rất khó hiểu.
Tài liệu tham khảo: Ngữ nghĩa cho các trường hợp ngoại lệ không chính xác , Simon Peyton Jones, Alastair Reid, Tony Hoare, Simon Marlow, Fergus Henderson. Thiết kế và triển khai ngôn ngữ lập trình Proc (PLDI'99), Atlanta. ( PDF )
throw
) và bạn có thể xác định ném một ngoại lệ throwIO
.
case error "banana" of (x:xs) -> error "bonobo"
có thể cung cấp cho bạn * Exception: bonobo
.