2010-05-28 3 views
2

я написал следующую программу:Странный тип связанных ошибка

isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]] 

primes = filter isPrime [1 .. ] 

он должен построить список простых чисел. Но я получил эту ошибку:

[1 of 1] Compiling Main    (7/main.hs, interpreted) 

7/main.hs:3:16: 
    Ambiguous type variable `a' in the constraints: 
     `Floating a' arising from a use of `isPrime' at 7/main.hs:3:16-22 
     `RealFrac a' arising from a use of `isPrime' at 7/main.hs:3:16-22 
     `Integral a' arising from a use of `isPrime' at 7/main.hs:3:16-22 
    Possible cause: the monomorphism restriction applied to the following: 
     primes :: [a] (bound at 7/main.hs:3:0) 
    Probable fix: give these definition(s) an explicit type signature 
        or use -XNoMonomorphismRestriction 
Failed, modules loaded: none. 

Если я указываю подпись для функции IsPrime явно:

isPrime :: Integer -> Bool 
isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]] 

Я не могу даже компилировать функцию IsPrime:

[1 of 1] Compiling Main    (7/main.hs, interpreted) 

7/main.hs:2:45: 
    No instance for (RealFrac Integer) 
     arising from a use of `truncate' at 7/main.hs:2:45-61 
    Possible fix: add an instance declaration for (RealFrac Integer) 
    In the expression: truncate (sqrt x) 
    In the expression: [2 .. truncate (sqrt x)] 
    In a stmt of a list comprehension: i <- [2 .. truncate (sqrt x)] 

7/main.hs:2:55: 
    No instance for (Floating Integer) 
     arising from a use of `sqrt' at 7/main.hs:2:55-60 
    Possible fix: add an instance declaration for (Floating Integer) 
    In the first argument of `truncate', namely `(sqrt x)' 
    In the expression: truncate (sqrt x) 
    In the expression: [2 .. truncate (sqrt x)] 
Failed, modules loaded: none. 

Можете ли вы помочь мне понять, , почему я получаю эти ошибки?

+0

Мое предположение - усечение & sqrt. Является ли замена truncate (sqrt x) на x работой? – 2010-05-28 04:42:25

ответ

9

Ваша проблема заключается в вызове sqrt x. Чтобы понять почему, давайте проверить тип isPrime в GHCi:

Prelude> let isPrime x = and [x `mod` i /= 0 | i <- [2 .. truncate (sqrt x)]] 
Prelude> :t isPrime 
isPrime :: (Integral a, Floating a, RealFrac a) => a -> Bool 

Это говорит нам о том, что вход isPrime может быть любого типа, который, как экземпляр все три указанные классы типа. Другими словами, число, которое одновременно является целым числом и вещественным числом с плавающей запятой. Хотя в принципе один может объявить такой тип, это не имеет большого смысла; и на самом деле такого типа не существует.

Теперь это объясняет обе ошибки. Первая ошибка заключается в том, что isPrime слишком полиморфен без сигнатуры типа. monomorphism restriction говорит (грубо говоря), что если вы определили значение через сопоставление с образцом (например, f = или Just x =, но не g y =), оно не должно быть полиморфным в классах. Таким образом, поскольку вы не указываете подпись типа для primes, она выводит тип primes :: (Integral a, RealFrac a, Floating a) => [a], а затем жалуется, так как он является полиморфным.

Вторая ошибка возникает из набора трех ограничений на классной знак, которые вы наложили. mod говорит, что x должен иметь тип, который является экземпляром Integral; sqrt говорит, что его вход должен иметь тип, который является экземпляром Floating; и truncate говорит, что результат sqrt (который имеет тот же тип, что и его вход) должен иметь тип, который является экземпляром RealFrac. Поскольку все они используются для выполнения идентичных переменных типа, x должен иметь все эти типы одновременно, а Integer не является ни одним экземпляром Floating, ни RealFrac. Следовательно, когда вы укажете, что isPrime :: Integer -> Bool, вы получите сообщение об ошибке, потому что Integer должен быть экземпляром Floating, но это не так. Чтобы решить эту проблему, мы можем сделать Hoogle для поиска a conversion function of type (Integral a, Floating b) => a -> b. Разумеется, Hoogle придумал более общий fromIntegral :: (Integral a, Num b) => a -> b; добавив, что до x в аргументе sqrt будут решены ваши проблемы, так как вы будете обрабатывать только x в качестве примера Integral.Это дает вам:

-- The one other change I made: only positive numbers are prime, and 1 is not a 
-- prime. 
isPrime :: Integral i => i -> Bool 
isPrime x | x <= 1 = False 
      | otherwise = and [ x `mod` i /= 0 
           | i <- [2..truncate . sqrt $ fromIntegral x] ] 

primes :: [Integer] 
primes = filter isPrime [2..] 

Обратите внимание, что благодаря ограничению мономорфизма, вам все равно нужно дать primes тип подписи! Но это, вероятно, хорошая идея.

4

isPrime x = and [x mod i /= 0 | i <- [2 .. truncate (sqrt (fromIntegral x))]]

Вам не хватает преобразования из интегральных типов в плавающие типы в аргументе для sqrt.

Смежные вопросы