Haskell/A Miscellany of Types
So far the only basic types we have looked at are Integers and Lists, although passing mention was made of strings and characters. This section will cover the major basic types.
An important thing to understand about the built-in types of Haskell is that they are not particularly special. From the compiler's point of view they are special because processors have special operations to do things like integer addition, but from the programmer's point of view they are just ordinary types with ordinary functions that follow exactly the same rules as any other type. Hence this section contains very little in the way of explanation on how you use these types or what the rules are, because for the most part you already know it: if it works for integers then it works for strings, booleans and floats.
Haskell has two types for integer numbers: Int and Integer.
"Integer" is an arbitrary precision type: it will hold any number no matter how big, up to the limit of your machine's memory. That is why "factorial 1000" gives you the right answer. This means you never have arithmetic overflows. On the other hand it also means your arithmetic is relatively slow. Lisp users may recognise the "bignum" type here.
"Int" is the more common 32 or 64 bit integer. Implementations vary, although it is guaranteed to be at least 30 bits.
Haskell also has two types for floating point: Float and Double. These behave like the corresponding types in C.
All the usual operators are there, along with some extras.
- Aside: Haskell numeric types are tied together in a complicated hierarchy of classes, which will be described later. The purpose of this page is to give you enough to do ordinary arithmetic without tripping over the type system.
There are three "raise to the power" operators which work differently and take different argument types.
- Takes two floating point numbers and uses logarithms to compute the power.
- Takes a fractional number (i.e. a floating point or a ratio, of which more later) and raises it to a positive or negative integer power.
- Takes any numerical type and raises it to a positive integer power.
Conversion from an integer type (Int or Integer) to anything else is done by "fromIntegral". The target type is inferred automatically. So for example:
n :: Integer n = 6 x :: Float x = fromIntegral n m :: Int m = 7 y :: Double y = fromIntegral m
will define x to be 6.0 and y to be 7.0.
Division of integers is a little complicated. If you use the ordinary "/" operator on integers then you will get an error message (although the expression "4/3" does work because Haskell helpfully promotes literal integers to floats where necessary). Instead integer division is done using a collection of named operators.
Haskell has a neat trick with operators: you can take any function that takes two arguments and use it like an operator by enclosing the name in back-ticks. So the following two lines mean exactly the same:
d = 7 `div` 3 d = div 7 3
With that in mind, here are the integer division operators:
- Returns the quotient of the two numbers. This is the result of division which is then truncated towards zero.
- Returns the remainder from the quotient.
- Similar to "quot", but is rounded down towards minus infinity.
- Returns the modulus of the two numbers. This is similar to the remainder, but has different rules when "div" returns a negative number.
Provided y is not negative then the following two equations will always hold:
(x `quot` y)*y + (x `rem` y) == x (x `div` y)*y + (x `mod` y) == x
Just as you can convert a function with two arguments into an operator, you can convert an operator into a function with two arguments: just put it in parentheses. So the following two lines mean the same thing:
(+) 3 4 3 + 4
This can also be done with any "incomplete" operator application:
(3+) 4 (+4) 3 -- not 3 (+4)
Haskell has a boolean type Bool, with two values: True and False. There are also two operators defined on the Bool type: && and ||.
Numbers, characters and strings can be compared using the usual comparison operators to produce a Bool value:
- Not equal.
- Less than or equal.
- Greater than or equal.
- Less than.
- Greater than.
(When you learn about type classes, note that the equality operators (==, /=) are part of the type class Eq, and the comparison operators (<=, >=, <, >) are part of the type class Ord.)
Haskell has an "if-then-else" clause, but because Haskell is a functional language it is more akin to the "? :" operator of C: rather than "doing" either the "then" clause or the "else" clause, the whole expression evaluates to one of them. For example, the factorial function could be written
factorial n = if n <= 0 then 1 else n * factorial (n-1)
The syntax of an if expression is:
if <condition> then <true-value> else <false-value>
If the condition is True then the result of the "if" is the true-value, otherwise it is the false-value.