September 15th, 2010, 10:24 AM

Haskell: Defining types for very simple functions
Hi, I have started learning haskell and can not work out how to make functions with two parameters such as this one that is supposed to calculate the result of
a + b + c when a^2 + b^2 = c^2
(sorry i didnt think it would matter if i dont put the code in PHP)
code:
getc :: Integer > Integer > Float
getc a b = ( a + b + sqrt( a^2 + b^2 ) )
I think the type signature is the problem but I do not know how to define it can someone please help.
Also, when do you use Int, Integer, Float, and Double?
Is it correct that Double covers all these types so I can always use Double? I just dont get it.
Thank you very much.
September 15th, 2010, 06:30 PM

There is no need to provide a type signature at all in this case. All your arguments are very simple so you're really not gaining much bugchecking by declaring the type.
How Haskell handles numbers is a bit of a complex topic. What you need to worry about here are the classes Integral and Floating and Num. Int and Integer are instances of Integral and Float and Double are instances of Floating and all four of those types are instances of Num.
The functions you're using are:
Code:
(+) :: (Num a) => a > a > a
(^) :: (Num a, Integral b) => a > b > a
sqrt :: (Floating a) => a > a
If you break down yout code into subexpressions, you'll get an error message that shows you which one is at fault:
Code:
getc :: Integer > Integer > Float
getc a b = sum_ab + sqrt_a2_b2
where sum_ab = a + b
sqrt_a2_b2 = sqrt sum_a2_b2
sum_a2_b2 = a2 + b2
a2 = a ^ 2
b2 = b ^ 2
Code:
Couldn't match expected type `Float'
against inferred type `Integer'
In the expression: sum_ab + sqrt_a2_b2
(+)'s signature says every argument and its return value must be of the same type, but a+b is an Integer, sqrt returns a some sort of Floating, and your function's signature says the output will be a Float. You need to make all these consistent.
Look up the function fromIntegral to help resolve this.
To answer your question about Int, Integer, Float and Double: Int is a fixedsize integer. If a value gets too large you get integer wrap around:
Code:
*Main> let x = 2000000000 :: Int
*Main> x
2000000000
*Main> x * 2
294967296
Integer on the other hand is variablelength. It can grow to hold any size number you want:
Code:
*Main> let x = 2000000000 :: Integer
*Main> x
2000000000
*Main> x * 2
4000000000
Float and Double are two different sizes of floating point numbers with Double able to store approximately twice as many digits as Float.
Code:
*Main> let x = 0.1234567890123456789 :: Double
*Main> x
0.12345678901234568
*Main> let x = 0.1234567890123456789 :: Float
*Main> x
0.12345679
Double can hold every value Float can, and usually can hold any value of Int as well. However Double cannot hold every value of Integer since an integer can grow to by any length, but Double can at most have 16 significant digits (Yes double will go up to values like 10^100, but only the most significant digits of that will be preserved). Also a Double cannot hold an exact value of a repeating decimal such as 1/3. Long, long story short: Integrals, Floating and Rational all have there place.
That's all very incomplete, but I'm already treading into tl;dr territory here so I'll stop here. If you would like some additional details ask and I'll see if I can dredge up a more complete explanation.
For future reference, surround your code with [code]...[/code] tags, This will preserve indentation (which is especially important for Haskell) as well as prevent the forum markup from mangling code. Also include the exact error message you get in your post. This makes it a lot easier to get help.
sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}>(\&Meh);
September 15th, 2010, 07:14 PM

hey thanks man, thats a big help.
but it raises the question when DO you need to speficy the type signature?
September 15th, 2010, 08:58 PM

Originally Posted by joeygalloway
but it raises the question when DO you need to speficy the type signature?
You very rarely NEED to, but it will make your life a lot more pleasant if you do so on any complex function. Type signatures allow the compiler to provide you with more meaningful error messages and to detect errors. If you leave off the type signature and write the method wrong, Haskell might be able to infer some typing that happens to work.
For example,
Code:
badMap f [] = []
badMap f (x:xs) = (f x) ++ (badMap f xs)  Oops ++ instead of :
Haskell sees no problem there, but I'll get a bizarre error message claiming that 3 implies lists are numbers (WTF?) when I try to use it:
Code:
*Main> badMap (+1) [1,2,3]
<interactive>:1:17:
No instance for (Num [a])
arising from the literal `3' at <interactive>:1:17
Had I declared a type signature the error message would have pointed at my mistake in badMap.
Or take this weird function:
Code:
values x = (sqrt x, x `div` 2)
Haskell has no problem compiling it, but you won't be able to ever call it. Declaring a type signature would point out the impossibility of x's type.
Other cases where type signatures are important are numeric literals (Haskell has to infer if '1' means the Integral, Fractional, Floating, etc.) and a few edges cases you'll probably never see.
sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}>(\&Meh);