Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real World Haskell book - asymptotic complexity of Logger monad example

I just reached Chapter 14 of Real World Haskell and was wondering about this yesterday.

In the Logger monad example, the bind function is implemented as follows:

-- (>>=) :: Logger a -> (a -> Logger b) -> Logger b
    m >>= k = let (a, w) = execLogger m
                  n      = k a
                  (b, x) = execLogger n
              in Logger (b, w ++ x)

where the 2nd element in the injector function contains our log messages, which are continuously being appended using ++. (Read online around here for more context.)

My question is.. wouldn't that make the runtime complexity using this Logger quadratic to the number of messages?

If I'm wrong, please help provide the correct analysis and big oh notation.

If I'm right, I'm hoping people who have more experience/insights with Haskell and the book can tell me some reasons of choosing that implementation, and why it is ok. In the previous chapter of the book there's a section that says this way of appending of list is bad, and teaches us the difference list technique. Why is this not being used here?

BTW I love the book, it's going to be a book I'll read cover to cover since a long long time.

like image 861
ryaner Avatar asked Nov 30 '25 14:11

ryaner


2 Answers

That's the standard (naive) encoding of the Writer monad, specialized to list output. It works well enough for the majority of uses, using the monoid instance for lists:

instance Monoid [a] where
        mempty  = []
        mappend = (++)

Alternatives with better complexity involve loggic to dlists, or even more efficiently, a text or builder monoid.

like image 154
Don Stewart Avatar answered Dec 03 '25 13:12

Don Stewart


Depending on the associativity of the computation, yes, that will have quadratic complexity. For example, if your computation associates to the right:

log 0 >> (log 1 >> (log 2 >> log 3))

then the complexity is linear. However, if it associates to the left:

((log 0 >> log 1) >> log 2) >> log 3

then the complexity is quadratic. It is just "forwarding" to the properties of the underlying monoid, here [],(++).

I imagine the reason for stating it this way is for simplicity. While it may not be efficient, it is completely obvious what is going on. However, as others have answered, this is just the Writer monad over the list monoid. You can get Writer by replacing [] with mempty and ++ with `mappend`, and then you can instantiate it with [] or DList or whatever you want. So using the concrete forms is not all that much clearer, IMO.

like image 38
luqui Avatar answered Dec 03 '25 13:12

luqui



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!