2012-10-03 105 views
3

,我有以下定義一個單子內部配套:避免模式在Haskell

env = DataMap.fromList [ 
       ("foo",42), ("bar",69), 
       ("baz",27), ("qux",0) 
       ] 


doSomething:: String → Writer [String] Int 
doSomething s = do 
      let v = DataMap.lookup s env 
      case v of 
       Nothing → fail $ s ++ " not found" 
       Just a → do 
          tell [s ++ " → " ++ (show a)] 
          return a 

真的很討厭我這個代碼有什麼用途DoSomething的內部配套的格局。它徹底打敗了使用monads的目的。有什麼方法可以在不使用monad變換器的情況下僅使用monadic函數來重寫doSomething函數?

+1

你不是應該使用['maybe'](http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Maybe.html#v:maybe )功能? –

+5

但是......這不正是monad變壓器的用途嗎?爲什麼不使用一個?特別是因爲你現在正在使用'fail',這並不是一個好習慣...... –

+0

Maybe函數是通過模式匹配實現的(http://www.haskell.org/ghc/docs/6.10.2 /html/libraries/base/src/Data-Maybe.html),所以它仍然在那裏,儘管你不必看它。 – rickythesk8r

回答

3

正如@larsmans說,最簡單的方法是使用maybe功能:

doSomething:: String -> Writer [String] Int 
doSomething s = maybe n (\a -> t a >> return a) $ DataMap.lookup s env where 
    n = fail $ s ++ " not found" 
    t a = tell [s ++ " -> " ++ show a] 

Monad的變壓器是沒有多大幫助這裏。你將需要一個到結合幾個計算失敗和寫。如果只有一個計算,你不需要單子。

此外,我會使用ErrorT變壓器和throwError函數報告錯誤,而不是fail。有關處理錯誤的可能方法,請參閱http://www.haskell.org/haskellwiki/Error_reporting_strategies

+1

我從來沒有想到失敗被鄙視!我讀了它,現在有道理。一切都很好,謝謝!我會看看ErrorT必須提供什麼。 – user1472346

+0

我更喜歡'EitherT'和http://hackage.haskell.org/package/errors,但第二個建議使用這樣的錯誤處理策略:) – singpolyma

0

這是一種笨重的,但它是如何做到這一點。

doSomething2 :: String -> Writer [String] Int 
doSomething2 s = 
    maybe (fail $ s ++ " not found") id $ do 
     a <- DataMap.lookup s env 
     return $ (tell [s ++ " -> " ++ show a] >> return a)