luispedro
luispedro

Reputation: 7024

Is it possible to force a type to a class in Haskell?

As an example, say I wish to implement a function which sums up a list of Nums. Halfway through coding it, I wish to debug it with Debug.Trace:

module T where
import Debug.Trace

dosum :: (Num a) => [a] -> a
dosum xs = dosum' 0 xs
    where
        dosum' n [] = n
        dosum' n (x:xs) = trace (show n) $ dosum' (n+x) xs

The problem is that this will not compile:

Could not deduce (Show a) arising from a use of dosum'
from the context (Num a)

I can add (Show a) to dosum and then remove it when I am finished debugging (in real life, I will want to have a type which is not necessarily in Show, but I will debug with integers). This can get cumbersome if there are a few functions involved and I keep adding removing Show a statements.

I want to have a function unsafeShow

unsafeShow :: a -> String

which works if a is Show a and is free to crash if it is not. Is this possible?

Upvotes: 14

Views: 866

Answers (6)

Don Stewart
Don Stewart

Reputation: 137997

This is not possible. (note 1)


1: An exception is that you can dump the heap structure of GHC's heap, via an a -> String function. You can e.g. always turn a value into a hexadecimal pointer value, via vacuum. This is unlikely to be what you want. This functionality is the same as that used by the GHCi debugger to show arbitrary heap values.

Upvotes: 3

John L
John L

Reputation: 28097

Usually I would comment out the type signature, but if a function is deep in the tree that gets annoying. You can try using rewrite rules to replace your polymorphic function with the modified variant.

-- original function, should add NOINLINE to make sure your rule gets a chance to fire.
{-# NOINLINE dosum #-}
dosum :: (Num a) => [a] -> a

-- a version with added debugging
dosumShow :: (Num a, Show a) => [a] -> a

{-# RULES "sub/dosum" forall x. dosum x = dosumShow x #-}

Upvotes: 1

Ben Millwood
Ben Millwood

Reputation: 7011

The really really terrible answer is to use unsafeCoerce from the Unsafe.Coerce module. It is as it sounds – it is a general tool for bypassing the type system, and if you get it wrong, you won't get a type error or an exception, you will get a segmentation fault.

In this case, you can unsafeCoerce a value that you already know is an Integer to Integer so that the type system can recognise that it's an integer too. Then you can show it as usual (make sure to give an explicit type signature, so show knows what it is showing – it can't infer, since unsafeCoerce can return any type!)

But if you accidentally call the code with unsafeCoerce on something other than an Integer, crashes, memory corruption, anything could happen – you've just completely thrown away your safety net.

In general, the only "safe" uses of unsafeCoerce are between types that you already know are equal, but the typechecker doesn't (or some other specialised use-cases, see the docs). Even then it will be heavily frowned upon by anyone reading your code unless your comments explain why it is the only option.

Upvotes: 10

JJJ
JJJ

Reputation: 2801

It's GHC version 7.4.1? From it release notes:

The Num class no longer has Eq or Show superclasses. A number of other classes and functions have therefore gained explicit Eq or Show constraints, rather than relying on a Num constraint to provide them.

You can make code that works with both Haskell98/Haskell2010 and GHC by:

  • Whenever you make a Num instance of a type, also make Show and Eq instances, and

  • Whenever you give a function, instance or class a Num t constraint, also give it Show t and Eq t constraints.

Your code works well in previous versions of GHC (I try in 7.0.4).

Upvotes: 0

ehird
ehird

Reputation: 40797

No, this is not possible. It would violate parametricity; a polymorphic function is not allowed to behave differently based on the specific type it is called with. It would also break the open world assumption, in that adding a Show instance for a type would change the behaviour of your program.

It could be a useful debugging aid, as something explicitly marked unsafe, but GHC does not support such a function, and I don't think its current implementation would permit the easy addition of one.

A possible alternative, if you have many functions with the same typeclass context that you want to do this with, and there is a conceptual semantic grouping to, would be to have a class like

class (Num a) => Number a
instance (Num a) => Number a

which you can use instead of Num in signatures, changing the declaration to (Num a, Show a) when debugging. (It would be better to pick a more meaningful name than Number, however!)

Upvotes: 13

MathematicalOrchid
MathematicalOrchid

Reputation: 62848

It's not possible to implement your unsafeShow function in pure Haskell. The GHC could provide one, but currently it doesn't.

You might check out the GHCi debugger, however. This allows you to print stuff out that doesn't have a Show instance. (Further, it allows you to avoid evaluating something that wouldn't otherwise be evaluated, which can be useful.)

Upvotes: 3

Related Questions