Skip to content

Typeclass instance selection depends on the optimisation level

(See the attached files for a minimal case.)

A file A defines a typeclass, and gives an incoherent instance for all types a, and exports a function relying on said typeclass. A file B defines some data types, makes them specific instances of that class, and uses the function defined in A. Which instance ends up being picked for B depends on the optimisation level those files are compiled with.

//A.hs//

class A a where
  someValue :: a -> Maybe Int

instance {-# INCOHERENT #-} A a where
  someValue = const Nothing

getInt :: A a => a -> Int
getInt x = fromMaybe 0 $ someValue x

//B.hs//

data B = B Int

instance A B where
  someValue (B x) = Just x

getBInt :: Int
getBInt = getInt $ B 42

//Main.hs//

main = print getBInt
  • *Upon compiling with -O0, this prints 42; upon compiling with -O2, this prints 0.**

(Interestingly, if the redundant class constraint is removed from getInt, then it always prints 0.)

Edited by Antoine Leblanc
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information