haskellNotes
haskellNotes
An Introduction
1
What is a Functional Language?
total = 0;
for (i = 1; i 10; ++i)
total = total+i;
3
Example
Summing the integers 1 to 10 in Haskell:
sum [1..10]
4
Historical Background
1930s:
? 8
Basic Structure
• Purely function
• Lazy evaluation
• Statically typed with strong typing
• Uses type inference (like Python)
• VERY concise – small and elegant code
• Types are KEY (like Java or C – but more)
10
Starting GHC on Flip server
The GHC interpreter can be started from the
Unix command prompt by simply typing ghci:
11
The GHCi prompt > means that the
interpreter is ready to evaluate an
expression.
For example:
12
The Standard Prelude: List
Madness!
Haskell comes with a large number of standard library
functions. In addition to the familiar numeric functions such
as + and *, the library also provides many useful functions
on lists.
Select the first element of a
list: > head [1,2,3,4,5]
1
13
Remove the first element from a list:
> [1,2,3,4,5] !! 2
3
Reverse a list:
f(a,b) + c d
f a b + c*d
17
Moreover, function application is assumed
to have higher priority than all other
operators.
fa+b
18
Examples
Mathematics Haskell
f(x) fx
f(x,y) fxy
f(g(x)) f (g x)
f(x,g(y)) f x (g y)
f(x)g(y) fx*gy
19
Types
All computation in Haskell is done via evaluation of
expressions to get values. Every value has an
associated type, and is a first class object.
Examples:
• Integer
• Int
• Float
• Char
• Integer->Integer
• [a] -> Integer
e :: t
> :t head
head :: [a] -> a
21
My First Script
When developing a Haskell script, it is useful to keep two
windows open, one running an editor for the script, and the
other running GHCi.
% ghci test.hs 22
Useful GHCi Commands
Command Meaning
Note:
• div is enclosed in back quotes, not forward;
• x `f` y is just syntactic for f x y.
• So this is just saying div (sum ns) (length ns)
24
GHCi does not automatically detect that the
script has been changed, so a reload
command must be executed before the new
definitions can be used:
> :reload
Reading file "test.hs"
> factorial 10
3628800
25
Functions are often done using pattern
matching, as well as a declaration of type
(more later):
26
Exercise
Write a program to find the number of
elements in a list. Here’s how to start:
27
Naming Requirements
• Function and argument names must begin with a lower-
case letter. For example:
xs ns nss
28
The Layout Rule
In a sequence of definitions, each definition
must begin in precisely the same column:
a = 10 a = 10 a = 10
b = 20 b = 20 b = 20
c = 30 c = 30 c = 30
29
The layout rule avoids the need for explicit
syntax to indicate the grouping of
definitions.
a = b + c a = b + c
where where
b = 1 means {b = 1;
c = 2 c = 2}
d = a * 2 d = a * 2
implicit explicit
grouping grouping
30
Exercise
Fix the syntax errors in the program
below, and test your solution using
GHCi.
N = a ’div’ length xs
where
a = 10
xs = [1,2,3,4,5]
31
What is a Type?
A type is a name for a collection of related
values. For example, in Haskell the basic
type
Bool
False True
32
Type Errors
Applying a function to one or more
arguments of the wrong type is called a type
error.
> 1 + False
Error
[‘a’,’b’,’c’] :: [Char]
In general:
[t] is the type of lists with elements of
type t.
35
Tuple Types
A tuple is a sequence of values of different
types:
(False,True) :: (Bool,Bool)
(False,’a’,True) :: (Bool,Char,Bool)
In general:
In general:
37
The arrow is typed at the keyboard as ->.
38
Curried Functions
Functions with multiple arguments are also
possible by returning functions as results:
39
As a consequence, it is then natural for
function application to associate to the left.
mult x y z
Means ((mult x) y) z.
length :: [a]
Int
41
Ranges in Haskell
As already discussed, Haskell has
extraordinary range capability on lists:
ghci> [1..15]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]
ghci> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
ghci> ['K'..'Z']
"KLMNOPQRSTUVWXYZ”
ghci> [2,4..20]
[2,4,6,8,10,12,14,16,18,20]
ghci> [3,6..20]
[3,6,9,12,15,18] 42
Infinite Lists
A few useful infinite list functions:
ghci> take 10 (cycle [1,2,3])
[1,2,3,1,2,3,1,2,3,1]
ghci> take 12 (cycle "LOL ")
"LOL LOL LOL "
43
List Comprehensions
Very similar to standard set theory list notation:
44
Pattern Matching
Functions can often be defined in many different ways using
pattern matching. For example
_ && _ = False
True && True = True
46
List Patterns
Internally, every non-empty list is
constructed by repeated use of an operator
(:) called “cons” that adds an element to the
start of a list.
[1,2,3,4]
Means 1:(2:(3:(4:
[]))).
47
Functions on lists can be defined using x:xs
patterns.
head :: [a] a
head (x:_) = x
49
Type Classes
In a typeclass, we group types by what
behaviors are supported. (These are NOT
object oriented classes – closer to Java
interfaces.)
Example:
ghci> :t (==)
(==) :: (Eq a) => a -> a -> Bool
56
Guarded Equations
As an alternative to conditionals, functions
can also be defined using guarded
equations.
abs n
|n0 =n
| otherwise = -n
58
Exercise
Create a function evens that
returns a list of even numbers from
a list.
59
Exercise
Create a function myElem that
returns True if an element is in a
given list and returns False
otherwise
myElem :: (Eq a) -> a -> [a] -> Bool
60
Exercise
Create a function isAsc that returns
True if if the list given is in
ascending order
61
Exercise
Create a list of the factors of an
integer
62
Lambda Expressions
Functions can be constructed without
naming the functions by using lambda
expressions.
x
x+x
For example:
const :: a b
a
const x _ = x
For example:
can be simplified
to
odds n = map (\x x*2 + 1) [0..n-
1]
66
Sections
An operator written between its two
arguments can be converted into a curried
function written before its two arguments by
using parentheses.
For example:
> 1+2
3
> (+) 1 2
3
67
This convention also allows one of the
arguments of the operator to be included in
the parentheses.
For example:
> (1+) 2
3
> (+2) 1
3
70
The Foldr Function
A number of functions on lists can be defined
using the following simple pattern of
recursion:
f [] = v
f (x:xs) = x f xs
sum [] =0
=0
v
product [] =1
v =
product (x:xs) = x * product xs 1
=*
v =
and [] = True
and (x:xs) = x && and xs
True
= &&
72
The higher-order library function foldr (fold
right) encapsulates this simple pattern of
recursion, with the function and the value v
as arguments.
For example:
foldr :: (a b b) b [a] b
foldr f v [] =v
foldr f v (x:xs) = f x (foldr f v xs)
sum [1,2,3]
=
foldr (+) 0 [1,2,3]
=
foldr (+) 0 (1:(2:(3:[])))
=
1+(2+(3+0))
=
6
Replace each (:)
by (+) and [] by
0.
75
For example:
product [1,2,3]
=
foldr (*) 1 [1,2,3]
=
foldr (*) 1 (1:(2:(3:[])))
=
1*(2*(3*1))
=
6
Replace each (:)
by (*) and [] by 1.
76
Now recall the reverse function:
reverse [] = []
reverse (x:xs) = reverse xs ++ [x]
For example:
Replace each (:)
by x xs xs ++
reverse [1,2,3] [x] and [] by [].
=
reverse (1:(2:(3:[])))
=
(([] ++ [3]) ++ [2]) ++ [1]
=
[3,2,1]
77
The library function all decides if every
element of a list satisfies a given predicate.
For example:
True
78
Type Declarations
In Haskell, a new name for an existing type
can be defined using a type declaration.
we can
define:
origin :: Point
origin = (0,0)
we can
define:
copy :: a Pair a
copy x = (x,x)
81
Data Declarations
A completely new type can be defined by specifying
its values using a data declaration.
• The two values Cat and Dog are called the constructors
for the type Pet.
• Type and constructor names must begin with an upper-
case letter.
• Data declarations are similar to context free grammars.
The former specifies the values of a type, the latter the
sentences of a language.
82
Values of new types can be used in the same
ways as those of built in types. For example,
given
data Answer = Yes | No | Unknown
we can
define:
answers :: [Answer]
answers = [Yes,No,Unknown]
we can
define:
square :: Float Shape
square n = Rect n n
85
Not surprisingly, data declarations
themselves can also have parameters. For
example, given
data Maybe a = Nothing | Just a
we can define:
86
Binary Trees
In computing, it is often useful to store data in a
two-way branching structure or binary tree.
3 7
1 4 6 9
87
We can now define a function for a traversal of
a binary tree:
88
Search trees have the important property that
when trying to find a value in a tree we can
always decide which of the two sub-trees it
may occur in:
import Data.List
ghci> :t putStrLn
putStrLn :: String -> IO ()
ghci> :t putStrLn "hello, world"
putStrLn "hello, world" :: IO ()
So putStrLn takes a string and returns an I/O
action (which has a result type of (), the
empty tuple).