Избегание мономорфизма в привязках let без аннотации типа

У меня есть некоторый код, использующий типы для устранения неоднозначности экземпляров (настоящий код использует синглтоны GHC.TypeLits для тегов типов, но я не думаю, что это уместно), и я хотел бы использовать привязку let, чтобы избежать дублирования на уровне текста; к сожалению, это мономорфизирует результат.

Ниже приведен пример проблемы:

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)

Приведенный выше код не компилируется (но, конечно, если я наберу аннотировать quux чтобы быть полиморфным, все работает нормально), справедливо жаловался, что не может соответствовать Int с Char, Есть ли какой-нибудь способ, которым я мог бы добиться успеха компиляции без аннотирования типа и без повторения bar undefined на каждом сайте использования?

1 ответ

Решение
{-# LANGUAGE NoMonomorphismRestriction #-}

Или если вы хотите что-то менее глобальное

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

Причина последней работы состоит в том, что привязки мономорфизируются только тогда, когда они не имеют аргументов слева от знака равенства.

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

Так чтобы получить quux чтобы не мономорфизировать, вы должны дать ему аргумент слева от знака равенства. Если quux это не значение, а функция, вы можете просто расширить ее, чтобы получить тот же эффект:

let quux x = bar undefined x in ...

Для первого не беспокойтесь о производительности - если вы всегда называете это как quux ()затем он будет встроен и сгенерирует тот же код, что и версия с явной сигнатурой типа.

Другие вопросы по тегам