Running the following in GHCi throws an error on stuff' 4
but not on stuff 4
. Why ?
Is there a way to fix it ? I would like to use MkStuff'
and not MkStuff
.
ghci>
:{
class MkStuff s m | m -> s where
stuff:: s -> m ()
instance MkStuff Int IO where
stuff = print
class MkStuff' s m | m -> s where
stuff' :: s -> m
instance MkStuff' Int (IO ()) where
stuff' = print
:}
ghci> stuff 4
4
ghci> stuff' 4
<interactive>:16:1: error: [GHC-39999]
• No instance for ‘MkStuff' Integer ()’ arising from a use of ‘it’
• In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
While I am not completely sure, I believe that this is what happens.
The GHCi has some magic inside. After entering an expression, GHCi roughly attempts the following:
Try to infer e :: IO a
for some a
. If possible:
a. Check if a
is a Show
type. If so, run action e
and then print its resulting value of type a
(unless a~()
).
b. Otherwise, run action e
and then print its resulting a
value.
Otherwise, try to infer e :: a
for some a
of class Show
. If possible, print the string obtained by show e
.
Otherwise, print a type error.
In your first case, when inferring stuff 4 :: IO a
GHCi can see that stuff 4 :: m ()
, hence m ~ IO
. That can be used to commit to your instance, and everything proceeds smoothly.
In your second case, when inferring stuff' 4 :: IO a
GHCi can see that stuff' 4 :: m
, hence m ~ IO a
. This is not enough to commit to the instance because the instance is about IO ()
, and a
has not (yet) been inferred as ()
. If another instance instance MkStuff' Char (IO Bool) where ...
existed it could provide another candidate, so we can not commit.
Failing in step 1., we turn to step 2. but no concrete a
can be found. Defaulting rules try a ~ ()
, hence your weird error
No instance for ‘MkStuff' Integer ()’
. Alas, this defaulting occurs too late in the process to allow committing to the IO instance.
Try making the instance head more general:
instance a ~ () => MkStuff' Int (IO a) where
stuff' = print
This correctly allows GHCi to commit to the instance. Note that you will not be able to add further instances involving IO
in this way.