2
votes

Ugh. The following code fails to compile:

factorsOf number = [(x, quot number x) | x <- [2..toInteger $ floor $ sqrt number], number `mod` x == 0]

The following error is thrown:

  • "No instance for (Floating Integer) arising from a use of `sqrt'"

Please help? I'm clearly not grokking Haskell coercion.

PS: Leaving off toInteger compiles but throws a type-ambiguity error at runtime.

1
floor takes a non-integer and returns an integer, no extra motions to do. sqrt on the other hand can’t take an integer, it’s the very first step that breaks.FrownyFrog
@FrownyFrog Omg. I knew I was being dense. Could you please make this an answer so's I can accept it?crisis.sheep
type-ambiguity error at runtime there's no such thing in Haskell.n. 1.8e9-where's-my-share m.
@n.m. Oh. Then I guess I mean whatever error is indicated by "Ambiguous type variable 'b0' arising from a use of 'print' prevents the constraint '(Show b0)' from being solved."crisis.sheep
That's a compile time error about print.n. 1.8e9-where's-my-share m.

1 Answers

6
votes

It is highly advisable to always start design of a Haskell function with the type signature, and only then write the implementation. In this case, you probably want

factorsOf :: Integer -> [(Integer, Integer)]

So, within factorsOf n = ..., the variable n will have type Integer. That's the problem: you're trying to take the square root of an integer, but sqrt is only defined on floating numbers. So you need to convert to such a number before taking the root. After the root, you'll then want to truncate back to an integer, but floor already does that. toInteger is not needed.

factorsOf :: Integer -> [(Integer, Integer)]
factorsOf n
     = [ (x, n`quot`x)
       | x <- [2 .. floor . sqrt $ fromIntegral n]
       , n `mod` x == 0
       ]