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?
The really really terrible answer is to use
unsafeCoercefrom theUnsafe.Coercemodule. 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
unsafeCoercea value that you already know is anIntegertoIntegerso 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, soshowknows what it is showing – it can’t infer, sinceunsafeCoercecan return any type!)But if you accidentally call the code with
unsafeCoerceon something other than anInteger, crashes, memory corruption, anything could happen – you’ve just completely thrown away your safety net.In general, the only “safe” uses of
unsafeCoerceare 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.