Я решаю интересный пример haskell, который нашел в Интернете, поэтому я кастрировал приведенный ниже код, чтобы все еще воспроизводить по типу ошибки, но не раскрывать никаких решений:
import Control.Monad
import Data.List(permutations)
permutationsUpTo :: Int -> [a] -> [[a]]
permutationsUpTo 0 _ = []
permutationsUpTo _ [] = []
permutationsUpTo n (x:xs) = (permutationsUpTo (n) (xs)) ++ permutations (x:xs)
-- function borrowed from rosetta code
nthRoot n x = fst $ until (uncurry(==)) (\(_,x0) -> (x0,((n-1)*x0+x/x0**(n-1))/n)) (x,x/n)
integerNthRoot n = ceiling . (nthRoot n) . fromIntegral
algorithm :: Int -> Int -> [[Int]]
algorithm x n = do
perm <- permutationsUpTo x [1..(integerNthRoot n x)]
guard ((sum perm) == x)
return perm
Когда я пытаюсь скомпилировать этот код, я получаю:
No instance for (RealFrac Int)
arising from a use of `integerNthRoot'
Possible fix: add an instance declaration for (RealFrac Int)
In the expression: (integerNthRoot n x)
In the second argument of `permutationsUpTo', namely
`[1 .. (integerNthRoot n x)]'
In a stmt of a 'do' block:
perm <- permutationsUpTo x [1 .. (integerNthRoot n x)]
Этот ответ был особенно полезен, помогая мне понять, что происходит, но я все еще могу Кажется, эта ошибка не исправлена.
Заранее спасибо!
2 ответа
Проблема возникла из-за вашего кода из Rosetta Code. Если вы изучили тип nthRoot
в GHCi, это было
nthRoot :: (Eq a, Fractional a) => a -> a -> a
Но то, что вы действительно хотели, было
nthRoot :: (Integral a, Eq b, Floating b) => a -> b -> b
Если вы добавите эту подпись типа, ваша ошибка возникнет из арифметики между n
, x
и x0
. Простое исправление:
nthRoot :: (Integral a, Eq b, Floating b) => a -> b -> b
nthRoot n x = fst $ until (uncurry (==)) (\(_, x0) -> (x0, ((n' - 1) * x0 + x / x0 ** (n' - 1)) / n')) (x, x / n')
where n' = fromIntegral n
Тогда ваша функция integerNthRoot
имеет тип
integerNthRoot :: (Integral a, Integral b, Integral c) => a -> b -> c
И algorithm
проверки типов.
Вы всегда должны добавлять свои сигнатуры типа в объявления верхнего уровня. Он поймает ваши ошибки за вас.
Поскольку у вас есть Eq b, Floating b
в nthRoot
, может быть лучше просто переключиться на использование Double
(предложено hlint). Тогда у тебя просто было бы
nthRoot :: Integral a => a -> Double -> Double
nthRoot = ...
И я заметил, что вы, вероятно, предпочли бы
integerNthRoot :: (Integral a, Integral b) => a -> b -> b
integerNthRoot = ...
Сигнатура типа algorithm
фиксирует тип n
как Int
, поэтому вам потребуется nthRoot (fromIntegral n)
.
(Это действительно, действительно помогает дать сигнатуры типа всему верхнему уровню в Haskell, даже если вы не пытаетесь отладить ошибку типа.)
Похожие вопросы
Связанные вопросы
Новые вопросы
haskell
Haskell - это функциональный язык программирования, отличающийся строгой статической типизацией, отложенной оценкой, обширной поддержкой параллелизма и параллелизма и уникальными возможностями абстракции.