3

我有以下定义:

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 中使用模式匹配。它完全违背了使用单子的目的。有没有什么方法可以只使用单子函数而不使用单子转换器来重写 doSomething 函数?

4

2 回答 2

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

于 2012-10-03T14:28:12.000 回答
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)
于 2012-10-05T02:11:20.530 回答