
Am Sonntag, 24. August 2008 19:38 schrieb Logesh Pillay:
I've written the following implementation of the algorithm in this article http://www.afjarvis.staff.shef.ac.uk/maths/jarvisspec02.pdf
sqRoot n scale = sqRoot' (5*n) 5 where sqRoot' a b
| floor (logBase 10 b) >= scale = div b 10 | a >= b = sqRoot' (a-b) (b+10) | otherwise = sqRoot' (a*100) ((100 * (div b
10)) + (mod b 10))
Since this involves whole numbers only, I was surprised by the following run-time error.
*Main> sqRoot 2 5
<interactive>:1:0: Ambiguous type variable `t' in the constraints: `RealFrac t' arising from a use of `sqRoot' at <interactive>:1:0-9 `Floating t' arising from a use of `sqRoot' at <interactive>:1:0-9 `Integral t' arising from a use of `sqRoot' at <interactive>:1:0-9 Probable fix: add a type signature that fixes these type variable(s)
What am I missing?
Logesh Pillay
There is no automatic conversion between different numeric types, you must do that explicitly, except for numeric literals. From the guard a >= b (and the expression a-b) follows that a and b must have the same type. From the expressions (b `div` 10) and (b `mod` 10) follows that that type must belong to the type class Integral. From the use of logBase follows that that type must belong to the type class Floating. Finally, from the use of floor follows that that type must also belong to the type class RealFrac. If you ask GHCi for the type of sqRoot, it will tell you: *Main> :t sqRoot sqRoot :: (Integral t, Floating t, RealFrac t, Integral b) => t -> b -> t The problem occurs when you want to evaluate sqRoot, because then the types t and b must be decided. Since only standard numeric type classes are involved, GHCi is willing to default the ambiguous types, so it will look if it can find a type which simultaneously belongs to all three type classes in the default list (I think the default list GHCi uses is (Integer, Double)). Of course it doesn't find such a type, so it complains. Note, however, that it doesn't complain about the scale parameter, that can be defaulted to Integer without any problem. The ugly (and insane) fix would be to provide instances of Fractional, RealFrac and Floating for Integer or an instance of Integral for Double. The good fix is to insert calls to the apprpriate conversion function where necessary, for example sqRoot n scale = sqRoot' (5*n) 5 where sqRoot' a b | floor (logBase 10 $ fromIntegral b) >= scale = div b 10 | a >= b = sqRoot' (a-b) (b+10) | otherwise = sqRoot' (a*100) ((100 * (div b 10)) + (mod b 10)) works. HTH, Daniel