In Haskell, everything’s an expression, and every expression has a type.
Haskell has a static type system, so it knows everything’s type at compile time. In GHCI, you can use
:t expr to get the type of
expr. For instance, the
:t (True, 'a') gives
(True, 'a') :: (Bool, Char) . (The notation ‘::’ is read as “has type”.)
Haskell also has type inference, meaning the Haskell compiler infers the type from context, unlike languages like Java where you have to explicitly state the type of everything. Despite this, you can still explicitly declare the type of functions, which is considered good practice. The type is typically declared on the line before the function definition, also using ‘::’ notation.
As an example, this line would go before a function
removeNonUppercase which filters a string to include only uppercase characters:
removeNonUppercase :: [Char] -> [Char].
[Char] -> [Char] is itself the type of the function: that of functions which map lists of Chars to lists of Chars.
As a less trivial example, the following could be the definition of a function which adds 3 numbers:
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
Int refers to the return type and the first 3 are the input parameters. (The notation seems to imply currying, but I’ll have to get into the details of that another time.)