2012-05-16 24 views
14

Tôi có một nhóm người dùng, nhóm và bản đồ giữa người dùng và nhóm. Tôi có các chức năng khác nhau để thao tác các bộ này, tuy nhiên, người dùng không thể thêm người dùng < -> lập bản đồ nhóm cho người dùng không tồn tại hoặc xóa nhóm mà vẫn có người dùng làm thành viên, v.v.Haskell "ngoại lệ"

Vì vậy, về cơ bản tôi muốn các chức năng này để ném "ngoại lệ" mà phải được xử lý một cách rõ ràng bởi người gọi.

đầu tiên tôi nghĩ đến việc trở về một cái gì đó như thế này:

data Return r e = Success r | Exception e 

Và nếu người gọi không mẫu trận đấu với các Exception, họ hy vọng sẽ nhận được một cảnh báo trình biên dịch, hoặc ít nhất có một thời gian chạy rõ ràng lỗi khi có sự cố.

Đây có phải là cách tiếp cận tốt nhất và có giải pháp được đóng gói sẵn không? Lưu ý tôi cần phải ném và bắt "ngoại lệ" trong mã thuần túy, không phải là IO Monad.

Trả lời

19

Có, đây là một cách tiếp cận tốt và nó nằm trong thư viện chuẩn: Return r e giống với Either e r. Bạn thậm chí có thể viết mã như bạn sẽ sử dụng ngoại lệ trong IO, quá (nghĩa là không phải xử lý rõ ràng các lỗi ở mỗi bước có khớp mẫu): ví dụ Monad để Either truyền bá lỗi, giống như đơn Maybe làm (nhưng với bổ sung e giá trị trong trường hợp có lỗi). Ví dụ:

data MyError 
    = Oops String 
    | VeryBadError Int Int 

mightFail :: T -> Either MyError Int 
mightFail a = ... 

foo :: T -> T -> Int -> Either MyError Int 
foo a b c = do 
    x <- mightFail a 
    y <- mightFail b 
    if x == y 
     then throwError (VeryBadError x y) 
     else return (x + y + c) 

Nếu mightFail a hoặc mightFail b lợi nhuận Left someError, sau đó foo a b c ý chí, quá; các lỗi được tự động truyền đi. (Ở đây, throwError chỉ là một cách tốt đẹp của văn bản Left, sử dụng các chức năng từ Control.Monad.Error; có cũng catchError để bắt những trường hợp ngoại lệ.)

11

Các Return r e loại mà bạn đang mô tả chính là loại tiêu chuẩn

data Either a b = Left a | Right b 

Bạn có thể muốn sử dụng cái gọi là "error monad" (một tên phù hợp hơn là "ngoại lệ monad") của gói mtl. (Hoặc, có ExceptionT trong gói monadLib nếu bạn không muốn sử dụng mtl.) Điều này cho phép bạn thực hiện xử lý lỗi bằng mã thuần túy bằng cách gọi throwErrorcatchError. Here bạn có thể tìm thấy ví dụ cho biết cách sử dụng nó.

Các vấn đề liên quan