Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding monomorphism in let bindings without type annotation

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?

like image 895
Alex R Avatar asked May 21 '26 03:05

Alex R


1 Answers

{-# LANGUAGE NoMonomorphismRestriction #-}

Or if you want something less global

let quux () = bar undefined in 
    print (idInt (quux ()) >> print (idChar (quux ()))

The reason the latter works is that bindings are only monomorphised when they have no arguments to the left of the equals sign.

let foo = \x y -> x + y   -- :: Integer -> Integer -> Integer
let bar x y = x + y       -- :: (Num a) => a -> a -> a

So to get quux to not monomorphize, you have to give it an argument to the left of the equals sign. If quux is not a value but a function, you can simply eta expand to get the same effect:

let quux x = bar undefined x in ...

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.

like image 63
luqui Avatar answered May 23 '26 21:05

luqui