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 => a
For 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.