Skip to content
AgileLogics
5 min read

Values and Basic Types

Prerequisites: Using GHCi

Every value in Haskell has a type. The basic ones:

Type Example values Meaning
Int 42, -7 Fixed-size integer (64-bit on modern machines)
Integer 2 ^ 100 Unbounded integer — never overflows
Double 3.14, 1.0e-3 Double-precision floating point
Bool True, False Boolean (capitalized)
Char 'a', '\n' A single Unicode character, in single quotes
String "hello" A list of characters, in double quotes
() () "Unit" — the type with one value, meaning "nothing useful"

Naming values

city :: String
city = "Lagos"

temperature :: Int
temperature = 24

isWarm :: Bool
isWarm = temperature > 20

main :: IO ()
main = do
  putStrLn city
  print temperature
  print isWarm
  print (2 ^ 64 :: Integer)
Lagos
24
True
18446744073709551616
  • name :: Type is a type signature; name = value is a definition.
  • Names of values and functions start with a lowercase letter; types and constructors (Int, True) start with an uppercase letter.
  • (2 ^ 64 :: Integer) is a type annotation inside an expression.

There are no variables to change

A definition names a value — it doesn't create a box you can overwrite:

count :: Int
count = 1
count = 2

main :: IO ()
main = print count
main.hs:3:1: error: [GHC-29916]
    Multiple declarations of `count'
    Declared at: main.hs:2:1
                 main.hs:3:1
  |
3 | count = 2

  | ^^^^^

Instead of changing a value, you compute a new one and give it a new name (or pass it to a function). It feels restrictive at first, but it removes a whole category of bugs: nothing can change behind your back.

Int versus Integer

main :: IO ()
main = do
  print (maxBound :: Int)
  print ((maxBound :: Int) + 1)
  print (2 ^ 70 :: Integer)
9223372036854775807
-9223372036854775808
1180591620717411303424

Int silently wraps around when it overflows; Integer grows as needed. Use Int for counts and indexes, Integer when numbers can get big.