A Taste of Haskell

Part 1

Haskell

  • Modern general-purpose programming language
  • Strong, static type system with type inference
  • Purely functional
  • Non-strict semantics (lazy evaluation)
  • High-performance parallel garbage collector
  • Light-weight concurrency library
  • Free and open

Haskell

  • Created in 1987 to unify several developments on functional programming
  • Named after mathematician Haskell Brooks Curry
  • Current language standard is Haskell 2010
  • The Glasgow Haskell Compiler (GHC) is the most commonly used compiler
  • Stack is a cross-platform tool for developing, testing, building, Haskell projects

Imperative vs. Functional Style

Imperative


    int total = 0;
    for (int n = 1; n <= 100; n++)
      if (n % 2 == 0)
        total += n;
          

Functional


total = sum (filter even [1..100])
          

Values

Defined with an equation


Prelude> a = 2
Prelude> 5 * a
10
Prelude> b = 10 * a
Prelude> b
20
Prelude> c = b < 100
Prelude> c
True
          

Values in Haskell are immutable

Functions

Defined with an equation, take one or more parameters


double x = 2 * x
          

Produce single result when applied to arguments


Prelude> double 5
10
          

Function application can be nested


Prelude> double (double 5)
20
          

Function Application

Parameters and arguments are separated by spaces


Prelude> add x y = x + y
Prelude> add 2 5
7
          

Function application has higher priority than other operators so f a + b means (f a) + b

Use parantheses to change order of evaluation, e.g.
f (a + b)

Value, Function and Parameter Names

  • Must begin with a lower-case letter
  • Followed by zero or more:
    • Lower- and upper-case letters
    • Digits, underscores, and foward single-quotes (')
  • Valid: myFunc, arg_1, x', x''
  • Invalid: MyFunc, 1arg, 'x

Basic Types

Bool Logical values True and False
Char Single characters 'a', 'B', '1'
String List of Chars "abc", "", "a"
Int Fixed precision 1, -10, 999
Integer Arbitrary precision 99999999999999
Float Single precision 1.0, -0.99
Double Double precision 999999999999.9

Types

The notation v :: T indicates v has type T


Prelude> :type True
True :: Bool
Prelude> :t 'a'
'a' :: Char
Prelude> :t "a"
"a" :: [Char]
          

Function Types

Every expression has a type, including functions


Prelude> :type not
not :: Bool -> Bool
Prelude> not True
False
Prelude> not False
True
          

Functions can be declared with a type


Prelude> :{
Prelude| happy :: Bool -> Bool -> Bool
Prelude| happy sunny cold = sunny && not cold
Prelude| :}
Prelude> happy True True
False
Prelude> happy True False
True
          

Type Inference

If not declared, types are inferred


Prelude> sad sunny cold = not sunny || cold
Prelude> :t sad
sad :: Bool -> Bool -> Bool
Prelude> sad True False
False

Prelude> double x = x * 2
Prelude> :t double
double :: Num a => a -> a
          

Num a => is a polymorphic constraint

Getting Help in GHCi


Prelude> :info Num
class Num a where
  (+) :: a -> a -> a
  (-) :: a -> a -> a
  (*) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
  {-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}
instance Num Word -- Defined in ‘GHC.Num’
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Int -- Defined in ‘GHC.Num’
instance Num Float -- Defined in ‘GHC.Float’
instance Num Double -- Defined in ‘GHC.Float’
          

Operators Are Functions

Normally written between two arguments (infix)


Prelude> :t (+)
(+) :: Num a => a -> a -> a
Prelude> 2 + 5
7
Prelude> :t (&&)
(&&) :: Bool -> Bool -> Bool
Prelude> True && False
False
          

Can also be used in prefix notation using brackets


Prelude> (+) 2 5
7
Prelude> (&&) True False
False
          

More Operators


Prelude> :t (==)
(==) :: Eq a => a -> a -> Bool
Prelude> 1 == 2
False
Prelude> :t (/=)
(/=) :: Eq a => a -> a -> Bool
Prelude> 1 /= 2
True
          

Functions can be used in infix notation using backticks


Prelude> :t div
div :: Integral a => a -> a -> a
Prelude> div 10 3
3
Prelude> 10 `div` 3
3
Prelude> 10 `mod` 3
1
          

Working with Negative Numbers

Binary subtraction operator and negate function


Prelude> :t (-)
(-) :: Num a => a -> a -> a
Prelude> 2 - 1
1
Prelude> :t negate
negate :: Num a => a -> a
Prelude> negate 1
-1
          

Unary minus is syntatic sugar for negate


Prelude> x = -1
Prelude> x
-1
Prelude> y = 2 * (-1)
Prelude> y
-2
          

Lists

Sequences of elements of the same type


Prelude> :t [True,False,True]
[True,False,True] :: [Bool]
Prelude> :t ['a','b','c']
['a','b','c'] :: [Char]
Prelude> :t ["abc","def"]
["abc","def"] :: [[Char]]
Prelude> :t []
[] :: [a]
          

The type of a list conveys no information about its length; in fact, lists can be infinite!

Working with Lists

The cons (:) and concatenation (++) operators


Prelude> :t (:)
(:) :: a -> [a] -> [a]
Prelude> 1 : []
[1]
Prelude> 1 : [2, 3]
[1,2,3]

Prelude> :t (++)
(++) :: [a] -> [a] -> [a]
Prelude> [1] ++ [2]
[1,2]
Prelude> [1,2] ++ [3,4]
[1,2,3,4]
Prelude> [] ++ []
[]
          

Useful List Functions


Prelude> head [1,2,3,4,5]
1
Prelude> tail [1,2,3,4,5]
[2,3,4,5]
Prelude> [1,2,3,4,5] !! 2
3
Prelude> take 3 [1,2,3,4,5]
[1,2,3]
Prelude> drop 3 [1,2,3,4,5]
[4,5]
Prelude> length [1,2,3,4,5]
5
            

Prelude> sum [1,2,3,4,5]
15
Prelude> product [1,2,3,4,5]
120
Prelude> reverse [1,2,3,4,5]
[5,4,3,2,1]
Prelude> filter odd [1,2,3,4,5]
[1,3,5]
Prelude> null [1]
False
Prelude> null []
True
            

Prelude is a module containing useful definitions and functions, included into all Haskell programs by default

Lazy Evaluation

Expressions are not evaluated until results are needed


Prelude> infinity = [1..]
Prelude> take 5 infinity
[1,2,3,4,5]
Prelude> take 10 infinity
[1,2,3,4,5,6,7,8,9,10]
Prelude> sum (take 1000 (filter even infinity))
1001000

Prelude> :t repeat
repeat :: a -> [a]
Prelude> repeatedOnes = repeat 1
Prelude> take 10 repeatedOnes
[1,1,1,1,1,1,1,1,1,1]
          

It is possible to force the evaluation of an expression, and Haskell libraries often come with strict variants

Tuples

Finite sequence of elements of possibly different types


Prelude> a = (True, False)
Prelude> :t a
a :: (Bool, Bool)
Prelude> b = (1, "haskell", not, (True, 'a'))
Prelude> :t b
b :: Num a => (a, [Char], Bool -> Bool, (Bool, Char))
Prelude> c = ()
Prelude> :t c
c :: ()
Prelude> d = ("tuple of arity one?")
Prelude> :t d
d :: [Char]
          

The number of elements in a tuple is called arity; tuples of arity one are not permitted!

Working with Tuples

Useful functions for tuples of 2 elements (pairs)


Prelude> :t fst
fst :: (a, b) -> a
Prelude> :t snd
snd :: (a, b) -> b
Prelude> fst (1, True)
1
Prelude> snd (1, True)
True          

Hoogle

Exercises

Part 1

Continue to part 2...