例如,我想开发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))")
答案 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)