Introduction To Haskell

Lecture 4


#SyntaxSwag

Using These Slides

Every slide has a secret note.

  • On Chrome: press F12, then click Console
  • On IE: press F12, then click Console
  • On Firefox: Ctrl+Shift+k


Shortcut Keys:

, PgDn, n, j next slide
, PgUp, p, k prev slide
Esc enables ctrl+f globally

Review

Haskell is

  • Purely functional
  • Statically typed
  • Lazy

Data looks like

  • Bool
  • Int
  • Char
  • ...

Lists and Tuples are useful data structures

List

[1,2,3]

Tuple

(1, "one")

More Review

Everything in Haskell has a Type

Here are some Type declarations.

These are your greatest weapons.


head :: [a] -> a -- gets the first element of a list

tail :: [a] -> [a] -- gets everything but the first element

last :: [a] -> a -- gets the last element of a list

init :: [a] -> [a] -- gets everything but the last element

(++) :: [a] -> [a] -> [a] -- concatenates two lists together

(:) :: a -> [a] -> [a] -- prepends an element to a list

fst  :: (a,b) -> a -- gets the first element of a tuple

snd  :: (a,b) -> b -- gets the second element of a tuple
	    

Review of Homework 3

Implement a Caesar Cipher
A
B
C
D

-- This example uses 'succ' to get next letter

cipher :: String -> Int-> String
cipher "" n = ""
cipher str n = rotate (head str) n : cipher (tail str) n

rotate :: Char -> Int -> Char
rotate c 0 = c
rotate c n = rotate (next c) (n-1)

next :: Char -> Char
next c = if c=='z' then 'a' else succ c
	    

Pattern Matching

A function can have multiple patterns

Almost like overloading methods in Java or C++


guess :: Int -> [Char]
guess 42 = "correct!"
guess x  = "wrong guess!"
	    

Each pattern has the same type declaration

Pattern Matching

  • Patterns are matched in order, top-down

  • Only the first matched pattern is evaluated

  • The patterns must exhaust the entire domain

What's wrong with this code?


fib :: Int -> Int
fib n = fib(n-1) + fib(n-2)
fib 0 = 1
fib 1 = 1
	    

The base case is never hit.

The first pattern eats up everything!

∞ loop

More Pattern Matching


You can even match lists using Construct


head (firstItem : everythingElse) = firstItem
	    

tail (x:xs) = xs
	    

More Pattern Matching

Write a function to detect if a list is a palindrome


isPal :: Eq a => [a] -> Bool



	    
(clear answer) (show answer)

Pattern matching is powerful

We can define fst with pattern matching


fst :: (a,b) -> a
fst (x,y) = x
	    

Try defining head with pattern matching


head :: [a] -> a



	      
(clear answer) (show answer)

Wildcard in Pattern Matching

  • We can specify when a value is unused.

  • The "_" symbol is called a wildcard in Haskell.

  • This is how it's used:

  • 
    head (x:_)  = x
    
    tail (_:xs) = xs
    	    

Error Handling

When GHCi is angry, it produces error messages through the error function.


error :: [Char] -> a
	    

The official implementation of head is


head             :: [a] -> a
head (x:_)       =  x
head []          =  error "Prelude.head: empty list"
	    

*

Guards

  • Guards are clean if statements.

  • Just like with pattern matching, order matters.

  • A guard is introduced by the | symbol.

  • And it's followed by a Bool expression.

  • Then followed by the function body

  • 
    guessMyNumber x
                | x > 27    = "Too high!"
                | x < 27    = "Too low!"
                | otherwise = "Correct!"
    	      
    otherwise is just a fancy word for True

Guards

Guards are very powerful.

Anything done with pattern matching can be done with guards.


head' :: [a] -> a
head' xs
    | null xs   = error "list is empty"
    | otherwise = xs !! 0
	      
!! is a function that gives an element at an index

Variables

These are not like your typical Java variables

In Java or C++, you can redefine variables:


x = 1;

...

x = 2;
	    

Mathematically, this makes no sense.

It implies 1=2 Preposterous!

Variables

Haskell variables are immutable.

Once defined, they can't change.


They can be used with the let keyword.


slope (x1,y1) (x2,y2) = let dy = y2-y1
                            dx = x2-x1
                        in dy/dx
	    

Or with the where keyword.


slope (x1,y1) (x2,y2) = dy/dx
                        where dy = y2-y1
                              dx = x2-x1
	    

Whitespace

In Haskell, indentation matters.

Code which is part of some expression should be indented further in than the beginning of that expression *

Level-1
    Level-2
              Level-3
              Level-3
              Level-3
    Level-2
     Level-3
     Level-3

Level-1
 Level-2
 Level-2

Level-1
	    
Don't use tab. Use spaces ' '.

Homework

A Useful Tool

  1. Fill out this week's form.
  2. Convert between metric and imperial.

    convert :: (Double, [Char]) -> (Double, [Char])

    • m ↔ yd
    • L ↔ gal
    • kg ↔ lb
    
    Prelude> convert (1, "m")
    (1.09361, "yd")
    Prelude> convert (1, "L")
    (0.264172, "gal")
    Prelude> convert (1, "kg")
    (2.20462, "lb")