2010-10-31 34 views
7

Tôi cần phải viết một đơn vị trạng thái cũng có thể hỗ trợ xử lý lỗi. Tôi đã nghĩ đến việc sử dụng một trong hai đơn nguyên cho mục đích này bởi vì nó cũng có thể cung cấp chi tiết về những gì gây ra lỗi. Tôi tìm thấy một định nghĩa cho một nhà nước monad sử dụng Có lẽ monad tuy nhiên tôi không thể sửa đổi nó để sử dụng Hoặc, thay vì Có thể. Đây là mã:Tôi có thể viết một đơn vị trạng thái xử lý lỗi như thế nào?

newtype StateMonad a = StateMonad (State -> Maybe (a, State)) 

instance Monad StateMonad where 
(StateMonad p) >>= k = StateMonad (\s0 -> case p s0 of 
           Just (val, s1) -> let (StateMonad q) = k val in q s1 
           Nothing -> Nothing) 
return a = StateMonad (\s -> Just (a,s)) 

data State = State 
{ log :: String 
, a :: Int} 

Trả lời

6

Có hai giải pháp khả thi. Một trong đó là gần gũi nhất với các mã mà bạn cung cấp trên là:

newtype StateMonad e a = StateMonad (State -> Either e (a, State)) 

instance Monad (StateMonad e) where 
    (StateMonad p) >>= k = 
     StateMonad $ \s0 -> 
      case p s0 of 
       Right (val, s1) -> 
        let (StateMonad q) = k val 
        in q s1 
       Left e -> Left e 
    return a = StateMonad $ \s -> Right (a, s) 

data State = State 
    { log :: String 
    , a :: Int 
    } 

các hình thức khác di chuyển xử lý lỗi trong việc xử lý nhà nước:

newtype StateMonad e a = StateMonad (State -> (Either e a, State)) 

instance Monad (StateMonad e) where 
    (StateMonad p) >>= k = 
     StateMonad $ \s0 -> 
      case p s0 of 
       (Right val, s1) -> 
        let (StateMonad q) = k val 
        in q s1 
       (Left e, s1) -> (Left e, s1) 
    return a = StateMonad $ \s -> (Right a, s) 

data State = State 
    { log :: String 
    , a :: Int 
    } 
+0

Tôi không thấy sự khác biệt giữa khối mã đầu tiên và khối thứ hai. Bạn đã nhầm lẫn bao gồm cùng một mã hai lần hay không, nếu không, bạn có thể làm rõ sự khác biệt không? – seh

+0

@seh, bắt tốt, nó được cập nhật –

+3

Cũng lưu ý rằng hai thao tác này có một chút khác biệt. Phiên bản thứ hai cho phép các lỗi có thể tiếp tục, trong khi phiên bản đầu tiên chấm dứt vào lỗi đầu tiên. Nếu bạn đang lập mô hình ghi nhật ký, hãy lưu ý rằng phiên bản đầu tiên cũng 'mất' nhật ký do lỗi. –

4

Bạn cần một máy biến áp đơn nguyên. Các thư viện biến áp đơn lẻ như mtl cho phép bạn soạn các trình đơn khác nhau để tạo một phiên bản mới. Sử dụng mtl, bạn có thể xác định

type StateMonad e a = StateT State (Either e) a 

cho phép bạn truy cập cả trạng thái và xử lý lỗi trong số StateMonad.

2

Bạn luôn có thể sử dụng trình biến đổi đơn vị ErrorT với một đơn vị trạng thái bên trong (hoặc ngược lại). Hãy xem phần máy biến thế của all about monads.

HTH,

+1

Cập nhật liên kết: http://www.haskell.org/haskellwiki/All_About_Monads – sinelaw

9

Xem xét sử dụng ExceptT từ Control.Monad.Trans.Except (thay vì sử dụng Hoặc).

import Control.Monad.State 
import Control.Monad.Trans.Except 
import Control.Monad.Identity 

data MyState = S 

type MyMonadT e m a = StateT MyState (ExceptT e m) a 

runMyMonadT :: (Monad m) => MyMonadT e m a -> MyState -> m (Either e a) 
runMyMonadT m = runExceptT . evalStateT m 

type MyMonad e a = MyMonadT e Identity a 
runMyMonad m = runIdentity . runMyMonadT m 

Nếu bạn không thoải mái với Monads và máy biến áp Monad sau đó tôi muốn làm điều đó đầu tiên! Họ là một trợ giúp rất lớn và lập trình hiệu suất năng suất lập trình.

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