Hiện trạng có thể không phải là những gì bạn muốn ở đây; không có cách nào để "quan sát" các loại thực tế được ràng buộc với e
hoặc w
trong giá trị Dangerous a
, vì vậy, bạn hoàn toàn bị giới hạn đối với các hoạt động được cung cấp cho bạn bởi Error
và Show
.
Nói cách khác, điều duy nhất bạn biết về w
là bạn có thể biến nó thành một String
, vì vậy nó có thể cũng chỉ là một String
(bỏ qua ưu tiên để đơn giản hóa mọi thứ), và điều duy nhất bạn biết về e
là bạn có thể biến nó thành một String
, bạn có thể biến String
giây vào đó và bạn có một giá trị phân biệt của nó (noMsg
). Không có cách nào để khẳng định hoặc kiểm tra xem các kiểu này có giống nhau hay không, vì vậy khi bạn đặt chúng vào một Dangerous
, không có cách nào để phục hồi bất kỳ cấu trúc đặc biệt nào mà các kiểu đó có thể có.
gì được thông báo lỗi được nói là, về cơ bản, loại hình cho runDangerous
tuyên bố rằng bạn có thể biến một Dangerous
thành một (Either e a, [w])
cho bất kỳe
và w
rằng có những trường hợp có liên quan. Điều này rõ ràng không đúng: bạn chỉ có thể biến một loại Dangerous
thành loại đó cho một lựa chọn e
và w
: loại được tạo. Các w1
chỉ vì loại Dangerous
của bạn được xác định với một biến loại w
, và như vậy là runDangerous
, do đó GHC đổi tên một trong số chúng để tránh xung đột tên.
Loại bạn cần phải cung cấp cho runDangerous
trông như thế này:
runDangerous
:: (forall e w. (Error e, Show e, Show w) => (Either e a, [w]) -> r)
-> Dangerous a -> r
đó, cho một chức năng mà sẽ chấp nhận một giá trị kiểu (Either e a, [w])
cho bất kỳ lựa chọn của e
và w
chừng nào họ có các trường hợp đã cho và Dangerous a
, tạo ra kết quả của hàm đó. Điều này là khá khó khăn để có được đầu của bạn xung quanh!
Việc thực hiện cũng đơn giản như
runDangerous f (Dangerous m) = f $ runState (runErrorT m) []
đó là một sự thay đổi không đáng kể đến phiên bản của bạn. Nếu điều này làm việc cho bạn, tuyệt vời; nhưng tôi nghi ngờ rằng một tồn tại là đúng cách để đạt được bất cứ điều gì bạn đang cố gắng làm.
Lưu ý rằng bạn cần {-# LANGUAGE RankNTypes #-}
để thể hiện loại runDangerous
. Ngoài ra, bạn có thể định nghĩa khác hiện sinh cho loại kết quả của bạn:
data DangerousResult a = forall e w. (Error e, Show e, Show w) =>
DangerousResult (Either e a, [w])
runDangerous :: Dangerous a -> DangerousResult a
runDangerous (Dangerous m) = DangerousResult $ runState (runErrorT m) []
và trích xuất kết quả với case
, nhưng bạn sẽ phải cẩn thận, hoặc GHC sẽ bắt đầu phàn nàn rằng bạn đã để cho e
hoặc w
thoát - tương đương với việc cố gắng truyền một hàm đa hình không đủ cho dạng khác của runDangerous
; tức là một yêu cầu có nhiều ràng buộc hơn về những gì e
và w
vượt quá loại bảo đảm runDangerous
.
Có cách nào tốt hơn (hoặc thành ngữ hơn) để thực hiện việc này không? Tôi thực sự chỉ muốn một lỗi đơn lẻ đi kèm với một số cảnh báo. – So8res
Tại sao không chỉ xác định loại là 'Nguy hiểm e w a'? Không cần thiết cho những tồn tại ở đây, nếu tôi hiểu những gì bạn đang cố gắng đạt được (điều mà tôi rất có thể không có). – ehird
Tôi có một vài mô-đun mà tất cả đều ném lỗi và cảnh báo của riêng họ và chúng được xử lý ở cấp cao nhất. Cấp cao nhất chỉ cần in chúng, nhưng nó gây phiền nhiễu khi nói 'Dangerous OptError OptWarning [Option]' trong mô-đun tùy chọn và 'Template Template Template Template nguy hiểm trong mẫu template, khi tất cả chúng chỉ là' show'n. Tôi đang cố gắng để loại bỏ rất nhiều boilerplate và tìm hiểu một chút gì đó, nó chắc chắn không cần thiết. – So8res