I've got some code using types to disambiguate instances (the real code is using GHC.TypeLits singletons for type tags, but I don't think that's germane) and I'd like to use a let binding to avoid text-level duplication; unfortunately, this monomorphizes the result.
What follows is an example of the problem:
class Foo a where
foo :: a
instance Foo Int where
foo = 0
instance Foo Char where
foo = 'a'
data Bar a = Bar String
deriving (Show)
bar :: forall a. (Show a, Foo a) => a -> Bar a
bar _ = Bar $ show (foo :: a)
idInt :: Bar Int -> Bar Int
idInt = id
idChar :: Bar Char -> Bar Char
idChar = id
main = let quux = bar undefined in
print (idInt quux) >> print (idChar quux)
The above code doesn't compile (but, of course, if I type annotate quux to be polymorphic, everything works fine), rightly complaining that it couldn't match Int with Char. Is there any way I could get compilation to succeed without type-annotating and without repeating bar undefined at each use site?
Or if you want something less global
The reason the latter works is that bindings are only monomorphised when they have no arguments to the left of the equals sign.
So to get
quuxto not monomorphize, you have to give it an argument to the left of the equals sign. Ifquuxis not a value but a function, you can simply eta expand to get the same effect:For the former, don't worry about performance -- if you always call it as
quux (), then it will be inlined and generate the same code as the version with an explicit type signature.