问题
I have the following function to return the Factor Pairs for a given number
factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0]
When I call the function in ghci factorPairs 18
I'm getting a run time error of
* Ambiguous type variable `a0' arising from a use of `it'
prevents the constraint `(Floating a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Floating Double -- Defined in `GHC.Float'
instance Floating Float -- Defined in `GHC.Float'
* In the first argument of `print', namely `it'
In a stmt of an interactive GHCi command: print it
I can hard code the function in ghci
map(\x -> (x, div 18 x)) [y | y <- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0]
and don't have any issues but I can't seem to figure out why my function is failing. I believe ghci is trying to tell me it can't figure out what type to call print
with but am struggling to find the solution.
回答1:
This has to do with the fact numeric literals are overloaded in Haskell. When you type map(\x -> (x, div 18 x)) [y | y <- [1..(ceiling $ sqrt 18)], 18 `rem` y == 0]
into ghci
, the 18
that is an argument to sqrt
defaults to a Double
and the others to Integer
s.
However, when you write
factorPairs:: (RealFrac a, Floating a, Integral a) => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt n)], n `rem` y == 0]
you force all instances of n
to have only one type. Then, the problem becomes that there simply are no default number types (in fact number types in general I think) that satisfy all of these constraints, hence GHC telling you about "possible instances" it tries. The solution is to add fromIntegral
and loosen the constraints:
factorPairs:: Integral a => a -> [(a, a)]
factorPairs n = map(\x -> (x, div n x)) [y | y <- [1..(ceiling $ sqrt $ fromIntegral n)], n `rem` y == 0]
回答2:
Another way to get rid of the type error is to eliminate the use of sqrt
. Since Haskell is lazy, you can simply iterate over [1..n]
, stopping when your divisor is greater than your quotient.
factorPairs :: Integral a => a -> [(a, a)]
factorPairs n = takeWhile (uncurry (>=)) [ (n `div` d, d) | d <- [1..n], n `mod` d == 0]
uncurry (>=)
is just a fancy way of writing \(q, d) -> q >= d
.
If you write this in monadic form, you can use divMod
to get the quotient and the remainder with a single function all.
factorPairs n = takeWhile (uncurry (>=)) $ do
d <- [1..n]
let (q, r) = n `divMod` d
guard $ r == 0
return (q, d)
来源:https://stackoverflow.com/questions/38531803/ambiguous-type-variable-a0-arising-from-a-use-of-it