# [Haskell-cafe] using the writer monad to better understand foldl and foldr, and haskell debugging techniques in general

Felipe Lessa felipe.lessa at gmail.com
Mon Feb 11 04:53:13 EST 2008

```On Feb 10, 2008 9:52 PM, Thomas Hartman <tphyahoo at gmail.com> wrote:
> So, I would say this proves my main point, which was that you could
> accomplish the same thing using the writer monad that you could do
> using the more "ad hoc" trace function from Debug.Trace.

Not really. That only happens with your implementation of myfoldrD. If
you write it as

myfoldrD' f z [] = z
myfoldrD' f z (x:xs) = x `f` trace ("x,r: " ++ (show (x,r))) r
where r = myfoldrD' f z xs

then we have the expected behavior

*Main> myfoldrD (:) [] [1..5]
x,r: (5,[])
x,r: (4,[5])
x,r: (3,[4,5])
x,r: (2,[3,4,5])
x,r: (1,[2,3,4,5])
[1,2,3,4,5]
*Main> myfoldrD' (:) [] [1..5]
[1x,r: (5,[])
x,r: (4,[5])
x,r: (3,[4,5])
x,r: (2,[3,4,5])
x,r: (1,[2,3,4,5])
,2,3,4,5]
*Main> myfoldrD const 0 [1..]
Interrupted.
*Main> myfoldrD' const 0 [1..]
1
*Main> myfoldrD (\x xs -> if x < 0 then [] else x:xs) [] ([1,2,3,-1]
++ repeat 0)
*** Exception: stack overflow
*Main> myfoldrD' (\x xs -> if x < 0 then [] else x:xs) [] ([1,2,3,-1]
++ repeat 0)
[1x,r: (3,[])
x,r: (2,[3])
x,r: (1,[2,3])
,2,3]

As Debug.Trace hides the IO monad in a pure computation (i.e.
unsafePerformIO) we can use it from the inside of the [pure] function
that is passed to foldr.

Note that we could also implement a Writer monad on top of
unsafePerformIO, you basically just change Debug.Trace to an IO action
that does the mappend as Writer would but in an IORef. In the end you
read that IORef and do a big tell to the outside Writer monad. I'd say
that this is a safe use of unsafePerformIO as it shouldn't break
referential transparency. But without this hack I don't think we could
do the same thing. Good news is that the hack is 'hideable' as are the
hacks from ByteString, for example.

Cheers,

--
Felipe.
```