#variables #haskell #types #literals
#переменные #haskell #типы #литералы
Вопрос:
Я использую ghci, и у меня возникла проблема с функцией для получения множителей числа.
Код, с которым я хотел бы поработать, это:
let factors n = [x | x <- [1..truncate (n/2)], mod n x == 0]
Она не жалуется, когда я нажимаю enter, но как только я пытаюсь ее использовать (в данном случае с 66) Я получаю это сообщение об ошибке:
Ambiguous type variable 't0' in the constraints:
(Integral t0)
arising from a use of 'factors' at <interactive>:30:1-10
(Num t0) arising from the literal '66' at <interactive>:30:12-13
(RealFrac t0)
arising from a use of 'factors' at <interactive:30:1-10
Probable fix: add a type signature that fixes these type variable(s)
In the expression: factors 66
In the equation for 'it': it = factors 66
Следующий код работает отлично:
let factorsOfSixtySix = [x | x <- [1..truncate (66/2)], mod 66 x == 0]
Я новичок в haskell, и после просмотра типов и классов типов я все еще не уверен, что я должен делать.
Комментарии:
1. Угадайте, что бы
n/2
вернулось!
Ответ №1:
Вместо этого используйте div
для целочисленного деления:
let factors n = [x | x <- [1.. n `div` 2], mod n x == 0]
Проблема в вашем коде заключается в том, что /
требуется RealFrac
тип для n
в то время mod
как Integral
один. Это нормально во время определения, но тогда вы не сможете выбрать тип, который соответствует обоим ограничениям.
Другим вариантом могло бы быть усечение n
перед использованием mod
, но это более громоздко. В конце концов, вы не хотите вызывать factors 6.5
, не так ли? 😉
let factors n = [x | x <- [1..truncate (n/2)], mod (truncate n) x == 0]
Ответ №2:
Если вы добавите аннотацию типа к этой привязке верхнего уровня (идиоматический Haskell), вы получите другие, возможно, более полезные сообщения об ошибках.
GHCi> let factors n = [x | x <- [1..truncate (n/2)], mod n x == 0]
GHCi> :t factors
factors :: (Integral t, RealFrac t) => t -> [t]
GHCi> let { factors :: Double -> [Double]; factors n = [x | x <- [1..truncate (n/2)], mod n x == 0]; }
<interactive>:30:64:
No instance for (Integral Double) arising from a use of `truncate'
Possible fix: add an instance declaration for (Integral Double)
In the expression: truncate (n / 2)
In the expression: [1 .. truncate (n / 2)]
In a stmt of a list comprehension: x <- [1 .. truncate (n / 2)]
GHCi> let { factors :: Integer -> [Integer]; factors n = [x | x <- [1..truncate (n/2)], mod n x == 0]; }
<interactive>:31:66:
No instance for (RealFrac Integer) arising from a use of `truncate'
Possible fix: add an instance declaration for (RealFrac Integer)
In the expression: truncate (n / 2)
In the expression: [1 .. truncate (n / 2)]
In a stmt of a list comprehension: x <- [1 .. truncate (n / 2)]
<interactive>:31:77:
No instance for (Fractional Integer) arising from a use of `/'
Possible fix: add an instance declaration for (Fractional Integer)
In the first argument of `truncate', namely `(n / 2)'
In the expression: truncate (n / 2)
In the expression: [1 .. truncate (n / 2)]
Ответ №3:
Я новичок в Haskell, поэтому, пожалуйста, простите мою смелость придумать ответ здесь, но недавно я сделал это следующим образом;
factors :: Int -> [Int]
factors n = f' [n `div` x | x <- tail f', x /= exc]
where lim = truncate (sqrt (fromIntegral n))
exc = ceiling (sqrt (fromIntegral n))
f' = [x | x <- [1..lim], n `mod` x == 0]
Я считаю, что это более эффективно. Вы заметите, если вам понравится;
sum (factors 33550336)