I have created a replacement Prelude for use in teaching beginning Haskell students, called FirstPrelude. One of the aims is to expunge type classes from the standard library so that error messages are more of the classic Hindley-Milner variety, rather than getting No instance
errors. This is working out quite well. However, something I did not anticipate is that, when pattern matching, GHC is side-stepping my redefinition of fromInteger
(defined as the identity, monomorphised to only work on Integer
) and so for example, with this function:
isZero 0 = True
isZero _ = False
If I ask GHCi for the type, I get:
isZero :: (GHC.Classes.Eq a, GHC.Num.Num a) => a -> Bool
But what I want is to get Integer -> Bool
. Dumping the simplified core out of GHC I can see it is using:
(GHC.Num.fromInteger @Integer GHC.Num.$fNumInteger 0)))
I would have thought it would just use my fromInteger :: Integer -> Integer
that is in scope, but alas no. Is there a way I can somehow prevent GHC.Num.fromInteger
from being used? I guess perhaps this possible at the package level, but really I would love this at the module level for other pedagogical reasons.
This is not tied to pattern matching: In your
Example.hs
, even literals in expressions are polymorphic. To see this, write something likeand observe the error message
You may not have noticed because as soon as you use one of “your” operations, GHC specializes the type, and for top-level values may use defaulting.
But note
for which it infers this type
If you enable
{-# LANGUAGE RebindableSyntax #-}
, it really uses “your”fromInteger
and things work as you expect. You can do that in the.cabal
file, maybe good enough for your educational needs.