Search code examples
haskellfunctional-programmingghcghciambiguous-type-variable

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.


Solution

  • 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]