views:

124

answers:

3

I want to use Debug.Trace.trace to print something which I know is a Show. Just like I would do in Python etc.

One solution is to add "Show a =>" to the signature of the function where I want to put the trace, and to any function calling it, etc.

But it would had been much nicer if I could use some debugShow function which calls show if the value has one, otherwise returns "--no show--" or something.

Here's my failed attempt to define a DebugShow (GHC rejects "Duplicate instance declarations"):

{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}

class DebugShow a where
  debugShow :: a -> String

instance Show a => DebugShow a where
  debugShow = show

instance DebugShow a where
  debugShow = const "--no show--"

Some kind of "unsafe cast" would also solve my problem.

Any advice?

Note - This is only for debugging purposes. I'm not using this in any finished code.

+1  A: 

"unsafe cast" is known as unsafeCoerce. Please observe the warnings in its documentation; it's an easy way to cause crashes and other foul behavior.

ephemient
@ephemient: thanks. in this case it seems I can use 'unsafeCoerce' to "cast" to a specific type, but I want to "cast" it to the same unknown type and add `Show` to its context. I tried to define "`debugShow = show . unsafeCoerce`" but that fails because of "`Ambiguous type variable`"
yairchu
+2  A: 

I'm not absolutely certain of this, but I think this is impossible without adding a class context to the entire call chain between the use site and the call site where each type variable is determined. The reason for this is operational: at least in GHC, each class is implemented by a dictionary. So at the use site we need a Show dictionary for a if one exists at all. But to get this we need it to have been passed down from the site where a was determined, and this requires something to be in the signature of all the intermediate functions.

Ganesh Sittampalam
+3  A: 

Perhaps you want some variant of:

traceShow :: (Show a) => a -> b -> b
traceShow = trace . show

defined in Debug.Trace

The constraint "calls show if the value has one, otherwise returns "--no show--" or something" is a hard one. You'll need overlapping (and incoherent) instances, I think, to define a default Show for all types (Perhaps via unsafeCoerce, or via vacuum).

Don Stewart
@dons: when you say via vacuum, what do you mean? is that a way to say that it can't be done?
yairchu
@yairchu I mean vacuum: http://hackage.haskell.org/packages/archive/vacuum/0.0.95/doc/html/GHC-Vacuum.html#v%3Avacuum which renders heap objects (i.e. doesn't need a Show dictionary)
Don Stewart
@dons: cool! this seems useful for debugging :)
yairchu