Expressions and Types
Just like we saw in the GHCi example above, expressions and types are the bread and butter of Haskell. In fact, almost everything in a Haskell program is an expression. In particular, there are no statements like in Python, Java or C.
An expression has a value and a type. We write an expression and its type like this: expression :: type. Here are some examples:
| Expression | Type | Value |
|---|---|---|
True | Bool | True |
not True | Bool | False |
'a' | Char | 'a' |
"as" ++ "df" | [Char] | "asdf" |
Syntax of Expressions
Expressions consist of functions applied to arguments. Functions are applied (i.e. called) by placing the arguments after the name of the function – there is no special syntax for a function call.
| Haskell | Python, Java or C |
|---|---|
f 1 | f(1) |
f 1 2 | f(1,2) |
Parentheses can be used to group expressions (just like in math and other languages).
| Haskell | Python, Java or C |
|---|---|
g h f 1 | g(h,f,1) |
g h (f 1) | g(h,f(1)) |
g (h f 1) | g(h(f,1)) |
Some function names are made special characters and they are used as operators: between their arguments instead of before them. Function calls bind tighter than operators, just like multiplication binds tighter than addition.
| Haskell | Python, Java or C |
|---|---|
a + b | a + b |
f a + g b | f(a) + g(b) |
f (a + g b) | f(a+g(b)) |
PS. in Haskell, function application associates left, that is, f g x y is actually the same as (((f g) x) y). We’ll get back to this topic later. For now you can just think that f g x y is f applied to the arguments g, x and y.
Syntax of Types
Here are some basic types of Haskell to get you started.
| Type | Literals | Use | Operations |
|---|---|---|---|
Int | 1, 2, -3 | Number type (signed, 64bit) | +, -, *, div, mod |
Integer | 1, -2, 900000000000000000 | Unbounded number type | +, -, *, div, mod |
Double | 0.1, 1.2e5 | Floating point numbers | +, -, *, /, sqrt |
Bool | True, False | Truth values | &&, ||, not |
String aka [Char] | "abcd", "" | Strings of characters | reverse, ++ |
As you can see, the names of types in Haskell start with a capital letter. Some values like True also start with a capital letter, but variables and functions start with a lower case letter (reverse, not, x). We’ll get back to the meaning of capital letters in the next part.
Function types are written using the -> syntax:
- A function of one argument:
argumentType -> returnType - … of two arguments:
argument1Type -> argument2Type -> returnType - … of three arguments:
argument1Type -> argument2Type -> argument3Type -> returnType
Looks a bit weird, right? We’ll get back to this as well.
Note About Misleading Types
Sometimes, the types you see in GHCi are a bit different than what you’d assume. Here are two common cases.
Prelude> :t 1+1
1+1 :: Num a => aFor now, you should read the type Num a => a as “any number type”. In Haskell, number literals are overloaded which means that they can be interpreted as any number type (e.g. Int or Double). We’ll get back to what Num a actually means when we talk about type classes later, in chapter 18.
Prelude> :t "asdf"
"asdf" :: [Char]The type String is just an alias for the type [Char] which means “list of characters”. We’ll get back to lists on the next chapter! In any case, you can use String and [Char] interchangeably, but GHCi will mostly use [Char] when describing types to you.
You can check your current points from the blue blob in the bottom-right corner of the page.