
On Thu, Mar 26, 2009 at 10:01:07PM +0000, Ivan Moore wrote:
Hi all,
consider this very small function:
thing n = n + round(sqrt n)
Here's what's going on: since you call sqrt on n, it must have some type which is an instance of Floating. However, round can return any type which is an instance of Integral, and since you are adding n to it, n must have the same type. This is the takeaway point here: sqrt requires some floating-point type (like Float or Double), but round returns an Integral type (like Int or Integer) and n can't be both. In particular you can't call sqrt on an Integral value. So the fix is to use fromIntegral to convert: thing n = n + round (sqrt (fromIntegral n))
It loads into ghci with no warnings.
The reason (which is a bit confusing) is that it typechecks just fine---if there *were* a type which is an instance of both Integral and Floating (and I guess round needs RealFrac as well), n could have that type. There isn't such a type in the standard libraries, but in theory you could make up your own type which is an instance of both.
When I try to run "thing 10" I get:
*Main> :load c:\temp\statictype.hs [1 of 1] Compiling Main ( C:\temp\statictype.hs, interpreted ) Ok, modules loaded: Main. *Main> thing 10
<interactive>:1:0: Ambiguous type variable `t' in the constraints: `Integral t' arising from a use of `thing' at <interactive>:1:0-7 `RealFrac t' arising from a use of `thing' at <interactive>:1:0-7 `Floating t' arising from a use of `thing' at <interactive>:1:0-7 Probable fix: add a type signature that fixes these type variable(s)
I have tried to add various type signatures (without really knowing what I'm doing!) and haven't been able to get it to work.
I am confused about a few things related to this: (a) what type signature fixes it and why it needs any help - it looks like the sort of thing that type inference shouldn't need any help with
The error message is particularly unhelpful here. Adding a type signature would only help if you actually had some type which was both Integral and Floating, but you don't.
(b) it looks like a runtime type error and I thought you didn't get runtime type errors in Haskell
You don't. This isn't a runtime type error; the error was generated while trying to typecheck the expression 'thing 10' before evaluating it.
(c) if I substitute 10 for n and do "10 + round(sqrt 10)" I get the expected answer 13
This is because numeric literals (like 10) are polymorphic---they can have any numeric type. In this case, type inference correctly figures out that the first 10 should have type Integer, and the second 10 should have type Double. The difference is that they are not constrained to have the same type---unlike the two occurrences of 'n' in your original function. Confusing, isn't it! It's a shame that numeric types can be so confusing, since that's usually one of the first things that people run into when learning the language. But I hope this is helpful. Feel free to ask if you have more questions. -Brent