2012-10-03 69 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)