Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GHCi not infering instance for some IO action

Tags:

haskell

ghci

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
like image 903
141592653 Avatar asked Oct 24 '25 16:10

141592653


1 Answers

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:

  1. 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.

  2. Otherwise, try to infer e :: a for some a of class Show. If possible, print the string obtained by show e.

  3. 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.

like image 120
chi Avatar answered Oct 26 '25 09:10

chi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!