Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ambiguous type variable `a0' arising from a use of `it'

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.

like image 408
CSharper Avatar asked Jul 22 '16 16:07

CSharper


2 Answers

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 Integers.

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]
like image 110
Alec Avatar answered Nov 11 '22 11:11

Alec


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)
like image 4
chepner Avatar answered Nov 11 '22 11:11

chepner