2014-11-24 67 views
3

我正在將我的大腦扭成節,試圖瞭解如何將State monad與Maybe合併。在State Monad上的錯誤處理中構建最小的Haskell示例

讓我們先從一個具體的(和故意瑣碎/不必要的)例子中,我們使用State單子找到數字列表的總和:

import Control.Monad.State 

list :: [Int] 
list = [1,4,5,6,7,0,3,2,1] 

adder :: Int 
adder = evalState addState list 

addState :: State [Int] Int 
addState = do 
    ms <- get 
    case ms of 
    []  -> return 0 
    (x:xs) -> put xs >> fmap (+x) addState 

酷。

現在讓我們修改它,使其返回Nothing,如果列表包含數字0。換句話說,evalState addState' list應該返回Nothing(因爲list包含0)。我想這可能是這個樣子......

addState' :: State [Int] (Maybe Int) 
addState' = do 
    ms <- get 
    case ms of 
    [] -> return (Just 0) 
    (0:xs) -> return Nothing 
    (x:xs) -> put xs >> fmap (fmap (+x)) addState' 

...它的工作原理,但我認爲有一個更好的方式來做到這一點...

我已經StateTMaybeT和玩耍了我無法讓他們工作。我已經看了一些對Monad變形金剛的介紹,但是他們或者沒有涉及到這個特殊的組合(即State + Maybe),或者這些例子太複雜了,以至於我無法理解。

TL; DR:我會很感激,如果有人可以顯示如何使用StateTMaybeT(兩個例子)來寫這個(當然微不足道)的代碼。 (我假設在不使用變壓器的情況下編寫此代碼是不可能的 - 是不正確的?)

P.S.我的理解是,StateT可能更適合這個例子,但從概念上講,如果不是太麻煩,看兩個例子都會有所幫助。

更新:正如@Brenton Alker指出的,由於簡單的錯字(我錯過了一個撇號),我上面的第一個版本的代碼不起作用。爲了集中關注使用StateT/MaybeT的問題,我正在糾正上面的帖子。只是想包括這個筆記給他的職位的背景。

回答

8

我會建議使用的類型是:用

StateT [Int] Maybe Int 

一個非常簡單的方法Maybe/MaybeT是隻叫mzero只要你想失敗,mplus每當你想從失敗的計算中恢復。即使它們在其他monad變換器中分層也是有效的。

下面是一個例子:

addState' :: StateT [Int] Maybe Int 
addState' = do 
    ms <- get 
    case ms of 
    []  -> return 0 
    (0:xs) -> mzero 
    (x:xs) -> put xs >> fmap (fmap (+x)) addState 

-- This requires generalizing the type of `addState` to: 
addState :: Monad m => StateT [Int] m Int 

請注意,我寫道,我沒有使用任何Maybe特異性操作的方式。事實上,如果你讓編譯器推斷類型簽名會推斷,而不是更一般的類型:

addState' :: MonadPlus m => StateT [Int] m Int 

這工作,因爲StateT具有以下MonadPlus實例:

instance MonadPlus m => MonadPlus (StateT s m) where ... 

而且Maybe將類型 - 請作爲MonadPlus的實例進行檢查,這就是爲什麼上述代碼適用於我們專門致力於mMaybe

+0

你我們如何運行這個'StateT'函數?你的代碼編譯(假設我在原始文章中糾正了@Brenton Alker指出的撇號),但我無法使用以下(在GHCi中)運行它:'evalState addState'list'。有什麼建議麼? – iceman 2014-11-24 02:29:23

+2

@DipakC,'evalStateT' – luqui 2014-11-24 02:40:52

1

我相信你的解決方案基本上是正確的,你只是有一些小問題。

  1. 您遞歸調用addState缺少素數 - 即。它應該是addState'(我懷疑這只是粘貼問題的問題,鑑於報告的錯誤)
  2. 你斷言adder :: Int,但在新的版本,它應該是adder :: Maybe Int - 我認爲這是錯誤的類型你」重新獲得。

不幸的是,我目前沒有資源嘗試變形金剛版本。

+0

是的,你的確是正確的:撇號... *紅臉* – iceman 2014-11-24 02:30:09