2014-10-16 3 views
2
{-# LANGUAGE NoMonomorphismRestriction #-} 
module Try where 

f :: IO (a -> IO String) 
f = return $ const getLine 

main :: IO() 
main = do 
    g <- f 
    :: IO (a -> IO String) 
    g "String" >>= print 
    g 5 >>= print 

Даже с NoMonomorphismRestriction флагом и явной сигнатуры типа, этот модуль не компилировать с Couldn't match expected type ‘[Char]’ with actual type ‘Int’, несмотря на g будучи полностью полиморфными.ограничение Мономорфизм в шаблон привязок

ответ

5

Это не то, что означает ограничение мономорфизма. Ограничение мономорфизма гласит, что если определение не имеет сигнатуры типа и имеет левую сторону без параметров, оно будет специализировано для мономорфного типа (или, скорее, достаточно мономорфного, чтобы избавиться от любых ограничений класса). Вы дали подписи типа, чтобы он не применялся.

Проблема в том, что вы указали неверный тип на f.

f :: IO (a -> IO String) 

фактически означает

f :: forall a. IO (a -> IO String) 

То есть, первого выбрать тип a, то вы можете связать, чтобы получить мономорфическую функцию типа a -> IO String для этого a. Там нет никаких проблем с этой программой, например:

main = do 
    g <- f 
    g "String" >>= print 
    g' <- f 
    g' 5 >>= print 

Но ваш пример использования требует такого типа:

f :: IO (forall a. a -> IO String) 

То есть, вы хотите связать первый и выбрать тип позже, т.е. использовать функция на нескольких типах. Это называется «непроизводительным типом», и, к сожалению, GHC не поддерживал их довольно долго, насколько мне известно.

Путь к решению этой проблемы, чтобы сделать newtype оболочку, которая явно количественно внутренний полиморфный тип:

newtype R = R { getR :: forall a. a -> IO String } 

f :: IO R 
f = return $ R (const getLine) 

main :: IO() 
main = do 
    g <- f 
    getR g "String" >>= print 
    getR g 5 >>= print 
+0

Спасибо! Я не был уверен, что это ограничение мономорфизма или нет, и самое близкое, что я мог найти, это «NoMonoPatBinds», но это тоже не помогло. – Fraser

+1

Стоит отметить, что единственные обитатели типа 'forall a. a -> IO String' являются элементами формы '\ _ -> x', где' x :: IO String'. Если для простоты нет дополнительной информации, то «R» должно быть просто «newtype R = R (IO String)», и в этом случае его можно обойти полностью. – user2407038