baron aron
baron aron

Reputation: 169

Haskell Monad.Writer

I am writing a logger for a sorting function like this:

bubble :: (Ord a) => [a] -> Writer [String] [a]
bubble (x:y:ys)  
        | x > y = do
                tell [show x ++ " why does this not work"]
                y:bubble(x:ys)
        | otherwise = do
                tell [show y ++ " is a number"] 
                x:bubble(y:ys)
bubble [x] = do 
            tell ["nothing works"]
            return [x] 

but i get this error:

 Couldn't match expected type `WriterT
                                    [String] Data.Functor.Identity.Identity [a]'
                with actual type `[a0]'
    In a stmt of a 'do' block: y : bubble (x : ys)
    In the expression:
      do { tell [show x ++ " why does this not work"];
           y : bubble (x : ys) }
    In an equation for `bubble':
        bubble (x : y : ys)
          | x > y
          = do { tell [show x ++ " why does this not work"];
                 y : bubble (x : ys) }
          | otherwise
          = do { tell [show y ++ " is a number"];
                 x : bubble (y : ys) }
Failed, modules loaded: none.

I have read this error message word for word but I am not any closer to what the problem is? I tried compiling with out the deceleration, for a fresh set of errors like this:

q.hs:21:17:
    No instance for (MonadWriter [[Char]] [])
      arising from a use of `tell'
    Possible fix:
      add an instance declaration for (MonadWriter [[Char]] [])
    In a stmt of a 'do' block:
      tell [show x ++ " why does this not work"]
    In the expression:
      do { tell [show x ++ " why does this not work"];
           y : bubble (x : ys) }
    In an equation for `bubble':
        bubble (x : y : ys)
          | x > y
          = do { tell [show x ++ " why does this not work"];
                 y : bubble (x : ys) }
          | otherwise
          = do { tell [show y ++ " is a number"];
                 x : bubble (y : ys) }
Failed, modules loaded: none.

Upvotes: 1

Views: 497

Answers (3)

Pharap
Pharap

Reputation: 4082

The message

Couldn't match expected type `WriterT [String] Data.Functor.Identity.Identity [a]' with actual type `[a0]' In a stmt of a 'do' block: y : bubble (x : ys)

Is referring to the fact that y:bubble(x:ys) has a type of [a] and bubble's is supposed to be a Writer [String] [a]. I.e. the types do not match.

y:bubble(x:ys) is just a list, but what you need it to be is a list embedded within your writer monad. In order to embed it as the result of your writer monad you need to use return.

  • y:bubble(x:ys) has a type of [a]
  • return $ y:bubble(x:ys) has a type of Writer [String] [a]

The same applies to x:bubble(y:ys). Thus your code ought to be:

bubble :: (Ord a) => [a] -> Writer [String] [a]
bubble (x:y:ys)  
        | x > y = do
                tell [show x ++ " why does this not work"]
                return $ y:bubble(x:ys)
        | otherwise = do
                tell [show y ++ " is a number"] 
                return $ x:bubble(y:ys)
bubble [x] = do 
            tell ["nothing works"]
            return [x] 

Upvotes: 0

dave4420
dave4420

Reputation: 47062

A nod in the right direction:

  1. What is the type of y?
  2. What is the type of bubble(x:ys)?
  3. What is the type of (:)?

Answers:

(In these answers, a is the same a as in bubble :: (Ord a) => [a] -> Writer [String] [a].)

  1. y :: a
  2. bubble(x:ys) :: Writer [String] [a]
    • bubble is a function, bubble(x:ys) is the result of applying bubble to x:ys
  3. (:) :: b -> [b] -> [b]
    • : is an operator; whatever type its first operand has, its second operand must have the type "list of whatever type the first operand has", and the result has that same list type.

Given that you have given y and bubble(x:ys) as the operands to :, can you see now what the problem is?

Upvotes: 3

mergeconflict
mergeconflict

Reputation: 8276

It's somewhat unfortunate, in cases like these, that Writer w a is a type synonym for WriterT w Identity a. It makes the compiler error messages (which are normally very informative) much harder to interpret. So my suggestion here is to simply ignore the content of the error message entirely and pretend you're the type checker.

@dave4420 provided a very good hint, I think. I'll add to that by saying: don't remove the type declaration for bubble - instead, go the opposite way: break bubble down into smaller helper functions, providing type declarations for each one. Then it should become much more clear where your problem lies.

My only other hint is that this is a common issue with writing monadic code: remembering which values are of monadic type, which aren't, and when to "lift."

Upvotes: 3

Related Questions