如何在foldl函数Haskell中记录操作?

时间:2015-04-17 16:37:50

标签: haskell

例如,我想开发sum函数,它将显示中期结果。

我的基本功能是:

ownPlus start list = foldr (+) start list

我想在foldl中添加Writer Monad。所以我的功能原型是:

sumWithLogging :: (Show a, Num a) => a -> [a] -> Writer String a
sumWithLogging start list = foldr ((+) do tell ["msg"]) start list

我在编写此函数时遇到问题。但我希望我的结果如下:

*Main> runWriter $ sumWithLogging 0 [1..2]
(3,"(1+(2+0))")

2 个答案:

答案 0 :(得分:5)

scanl 可能是一项有用的功能。

来自Hoogle:

  

scanl类似于foldl,但返回左侧连续减少值的列表。

所以,你可以看到渐进的结果:

λ> scanl (+) 0 [1,2,3]
[0,1,3,6]
λ> scanl (flip (:)) [] [1,2,3,4,5]
[[],[1],[2,1],[3,2,1],[4,3,2,1],[5,4,3,2,1]]

如果你想要类似作家的结果,那很简单。您甚至不需要使用Writer,并且避免使用过于复杂的功能总是很好。

logSum = foldl (\(n,s) x -> (n+x, "(" ++ s ++ "+" ++ show x ++ ")")) (0,"0")

λ> logSum [1..2]
(3, "((0+1)+2)")

我可能会补充说foldl应该描述左关联操作,但括号暗示正确的关联性就像你写的那样。

如果你希望它是右关联的(比如(:)运算符),那很简单;使用foldr

 logSumR = foldr (\x (n,s) -> (x:n, show x ++ " : " ++ s)) ([],"[]")

那样:

λ logSumR [1,2,3,4,5]
([1,2,3,4,5], "1 : 2 : 3 : 4 : 5 : []")

答案 1 :(得分:2)

如果您对括号不太在意,以下可能是一个很好的起点:

sumWithLogging :: (Show a, Num a) => a -> [a] -> Writer String a
sumWithLogging start list = foldlM step start list <* tell (show list)
    where step acc item = tell (show item ++ "+") >> return (item+acc)