0% found this document useful (0 votes)
40 views

Chapter 1: Problem Solving, Programming, and Calculation: Bjorn - Lisper@mdh - Se

The document provides an overview of functional programming concepts including computation by calculation, values, expressions, types, and declarations. It introduces the Haskell programming language and provides examples of basic language elements like numerical types, characters, booleans, conditionals, and functions. It discusses key functional programming concepts like pure functions without side effects, recursion, and evaluation through calculation rather than state changes.

Uploaded by

Gil Cartunista
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
40 views

Chapter 1: Problem Solving, Programming, and Calculation: Bjorn - Lisper@mdh - Se

The document provides an overview of functional programming concepts including computation by calculation, values, expressions, types, and declarations. It introduces the Haskell programming language and provides examples of basic language elements like numerical types, characters, booleans, conditionals, and functions. It discusses key functional programming concepts like pure functions without side effects, recursion, and evaluation through calculation rather than state changes.

Uploaded by

Gil Cartunista
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 99

Overview

Chapter 1: Problem Solving, Programming, and Calculation


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007

Basic concepts of functional programming: computation by calculation, values, expressions, types, declarations First glance of Haskell: introduction, basic language elements Some simple functional programming examples/exercises

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

Computation by Calculation
In ordinary programming languages, computation alters state by writing new values to program variables:
State before: x = 3, y = 4 x = 17 + x + y State after: x = 24, y = 4

In (pure) functional languages, computation is simply calculation:

3 * (9 + 5)

= =

3 * 14 42

This means you perform computations in sequence There is a control ow that decides this sequence:
for(i=0,i++,i<17) { if (j > i) then x++ else y++; x = y + j; }
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 2

Forget about assignments, sequencing, loops, if-then-else, . . . Forget everything you know about programming! (Well, almost) You might wonder how to do useful stuff just by calculating, well see later . . .

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

Functions
In functional languages we have: functions recursion (instead of loops) expressive data types (much more than numbers) advanced data structures and calculation on top of that Functions, mathematically: sets of pairs where no two pairs can have the same rst component: f = {(1, 17), (2, 32), (3, 4711)} f (2) = 32 Or, given the same argument the function always returns the same value (cannot have f (2) = 32 and f (2) = 33 at the same time) Functions model determinism: that outputs depend predictably on inputs Something we want to hold for computers as well . . .
4 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 5

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

Recursion
Dening a function by writing all pairs can be very tedious Often dened by simple rules instead simple (x, y, z ) = x (y + z ) These rules express abstraction: that a similar pattern holds for many different inputs (For all x, y, z , simple (x, y, z ) equals x (y + z )) Abstraction makes denitions shorter and easier to grasp A good property also for software, right? Mathematical functions are often specied by recursive rules Recursion means that a dened entity refers to itself in the denition This seems circular, but can make sense Example: the factorial function ! on natural numbers 0! = 1 n! = n (n 1)!, n > 0 Recursion corresponds to loops in ordinary programming
6 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 7

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

Pure Functional Languages


Pure functional languages implement mathematical functions A functional language is pure if there are no side-effects A side effect means that a function call does something more than just return a value An example in C:
int f(int x) { n++; return(n+x); }

Side effect for f: global variable n is incremented for each call This means that f returns different values for different calls, even when called with the same argument Much harder to reason mathematically about such functions: for instance, f(17) + f(17) = 2*f(17) Side effects requires a more complex model, and thus makes it harder to understand the software

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

In pure functional languages, functions are specied by side-effect free rules (declarations) In Haskell: simple x y z = x*(y+z) Each rule denes a calculation for any actual arguments: simple 3 9 5 = = = 3 * (9 + 5) 3 * 14 42

Exercise

Calculate simple (simple 2 3 4) 5 6 Note that we can do the calculation in different order Do we get the same result? More on this later . . .

Just put actual arguments into the right-hand side and go! Compare this with an execution model that must account for side-effects
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 10 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 11

Expressions, Values, and Types


The mathematical view makes it possible to prove properties of programs When calculating, all intermediate results are mathematically equal : simple 3 9 5 = 3 * (9 + 5) = 3 * 14 = 42 For instance, prove that simple x y z = simple x z y for all x, y, z: simple x y z = x * (y + z) = x * (z + y) = simple x z y We cannot do this for functions with side-effects
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 12 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 13

Calculation is performed on expressions: simple (simple 2 3 4) 5 6 Expressions are calculated into values: simple (simple 2 3 4) 5 6 = 154 Values are also expressions, which cannot be calculated any further

We said a calculation always ends in a value But what about x dened below?

Types
Many programming languages have types

x = x+1 x = x+1 = (x+1)+1 = ((x+1)+1)+1 = . . . Calculating x yields a never-ending calculation! No value will ever be returned (In reality, the Haskell system will break the computation when it is out of memory.) We denote this no-value by is called bottom (for mathematical reasons), think of it as no information
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 14

Types help avoiding certain programming errors, like adding an integer with a character A programming language can be: strongly typed : every program part must have a legal type weakly typed : every program part can have a legal type, but need not have untyped : no types exist
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 15

A First Introduction of Haskell

Haskell implementations
Three maintained public domain implementations exist: hugs, an interpreter GHC, an optimizing compiler nhc, a compiler producing compact code All are freely available from www.haskell.org In this course we use hugs, but you are free to try the others (The graphics library for the course book requires hugs, though)
16 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 17

Haskell is a strongly typed, purely functional language It uses lazy evaluation (dont compute anything before its needed) It is higher order (functions are ordinary data) It has a polymorphic type system, with type inference It has type classes (somewhat similar to classes in object-oriented languages) It has a lot of syntactic facilities to help write clear and understandable programs
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

Basic Language Elements of Haskell

Numerical Types
Haskell has a number of numerical types: Integer Int Float Double Rational Integers of arbitrary size (0, -3, 5487357384578349545, . . .) Integers of limited size (1, -3, 54873, . . .) Single precision oats (1, 1.0, 3.14159, 3.2E3, . . .) Double precision oats (1, 1.0, 3.14159, 3.2E3, . . .) Exact rational numbers (1, 3.5, 7 % 2, 3.2E3, . . .)

A rst introduction: Values Types (atomic values, composed values) Operators and predened functions Other syntactic forms

Functions and operators on numeric types are the usual ones: +, -, * (all numeric types), / (not integer types), ** (oating-point exponentiation), ^ (exponentiation with integer) Most typical numerical functions

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

18

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

19

Characters
Numerical expressions look like in most languages: x + 7*y 3.14159/(x + 1.0) - 33 (x + 7*y is the same as x + (7*y), since * binds stronger than +) Note that integer constants like 17 can assume any numeric type, depending on context So in x+17, 17 will get the same type as x Type Char for characters Syntax: a, b, \n (newline), . . .) Characters are elements in strings More on strings later

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

20

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

21

Booleans

Conditional

Type Bool for the two booleans values True, False Boolean operators and functions: && (and), || (or), not Relational operator returning a boolean value: ==, /=, <, <=, >=, > Can compare elements from any comparable type (more on this later)

Haskell has a conditional if-then-else expression: if True then x else y = x if False then x else y = y So we can write expressions like if x > 0 then x else -x However, the two branches must have the same type Thus, if x > 0 then 17 else a is illegal

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

22

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

23

Functions
Functions take a number of arguments and return a result Some predened ones, and you can dene your own A little unusual syntax: no parentheses around arguments sqrt 17 mod 17 3 (There are good reasons for this syntax, more on this later) The space between function and argument can be seen as a special operator: function application Function application binds harder than any other operator Thus, f x + y means (f x) + y, not f (x + y) (Common beginners mistake to forget this)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

24

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

25

Declarations

Types of Dened Entities


Note that we did not give any types in the denitions

You can dene your own entities Entities of any type can be dened by a declaration pi = 3.14159 denes pi to be a oating-point constant simple x y z = x*(y+z) denes simple to be a function in three arguments

Haskell manages to nd types automatically! This is called type inference However, we can also give explicit types (sometimes useful) e :: t declares e to have type t For instance: pi :: Float declares pi to be a single precision oat pi :: Double declares pi to be a double precision oat What about pi :: Char?

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

26

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

27

Recursive Denitions

Factorial in Haskell

As a rst exercise, recall the factorial function: 0! = 1 n! = n (n 1)!, n > 0 Dene it in Haskell! (Answer on next slide)

fac n = if n == 0 then 1 else n * fac (n-1) Exercise: Calculate fac 3

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

28

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

29

fac 3 = if 3 == 0 then 1 else 3 * fac (3-1) = if False then 1 else 3 * fac (3-1) = 3 * fac (3-1) = 3*(if (3-1) == 0 then 1 else (3-1) * fac ((3-1)-1)) = 3*(if 2 == 0 then 1 else 2 * fac (2-1)) = 3*(if False then 1 else 2 * fac (2-1)) = 3*2 * fac (2-1) ...etc... = 3*2*1 * fac (1-1) = 3*2*1*1 = 6 Eventually well reach the base case fac 0. This is what makes recursion work here!
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 30

Pattern Matching in Declarations


Another way to write the factorial function: use patterns Haskell allows to dene functions case-by-case, for different forms of the argument Every case has a pattern for the argument Cases are checked in order, the rst that matches the argument is selected For atomic types like numeric types, the possible patterns are constants So we can dene fac like this instead: fac 0 = 1 fac n = n * fac (n-1)
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 31

Nontermination and Errors

The Haskell Error Function

Now what about fac (-1)? fac(-1) = (-1)*fac(-2) = (-1)*(-2)*fac(-3) = Innite recursion! Will never terminate. (Same problem as with x = x+1) Thus, fac(-1) = Remember fac is really just dened for natural numbers, not for negative numbers Its good practice to have controlled error handling of out-of-range arguments

Haskell has an error function, that when executed prints a string and stops the execution E.g., error "You cannot input this number to this function" (Strings in Haskell are written within quotes, like "Hello world")

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

32

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

33

Accumulating Arguments
A version of fac with error handling: fac 0 = 1 fac n = if n > 0 then n * fac (n-1) else error "Negative argument to fac" Would we be able to write this case-by case (n > 0, n == 0, n < 0)? Not by pattern-matching, but there are other ways. More on this later Another way to dene the factorial function in Haskell: fac n = fac1 1 n fac1 acc 0 = acc fac1 acc n = fac1 (n*acc) (n-1) This solution uses a help function fac1 with two arguments The second argument is an accumulating argument, where we successively collect the result

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

34

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

35

Local Denitions
Note similarity with a loop with two variables: while (n \= 0) { acc = n*acc; n = n-1; } Exercise: calculate fac 3 with this new denition The fac version with accumulating argument uses a help function fac1 This function is globally dened However, only used by fac We may want to hide it in the denition of fac Haskell has a let-construct for local denitions: fac n = let fac1 acc 0 = acc fac1 acc n = fac1 (n*acc) (n-1) in fac1 1 n

Denes fac1 locally in the expression after in, which is the right-hand side in the declaration
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 36 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 37

Function Types
let-expressions are ordinary expressions and return values, can be used wherever ordinary expressions can be used: 17 + let x = fac 3 in x + 3*x = 17 + let x = 6 in x + 3*x = 17 + (6 + 3*6) = 41 Also note that the dened entity (x here) only needs to be computed once saves work! So let can be used also to save work when the same result is to be used many times A function that takes an argument of type a and returns a value of type b has the function type a -> b For instance, fac :: Integer -> Integer (Note resemblance with mathematical notation) What about functions with several arguments? simple x y z = x*(y+z) simple :: Integer -> Integer -> Integer -> Integer Last type is result type, preceding types are the respective argument types (Well explain later why multi-argument function types look this way)
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 38 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 39

Types for Data Structures


Haskell has two predened types for data structures: tuples and lists Lists are very important data structures in functional programming They are sequences of elements Lists can be arbitrarily long, but (in Haskell) all elements must be of the same type If a is a type, then [a] is the type list of a E.g. [Integer], [Char], [[Integer]], [Float -> Integer] A list can contain elements of any type (as long as all have the same type)
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 40

Constructing Lists

Lists are built from: the empty list : [] the cons operator, which puts an element in front of a list: : Example: 1:(2:(3:[])) : and [] are called constructors: they construct data structures (Constants like 17 and x are also constructors, but they only construct themselves)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

41

To the left is a graphical picture of [1,2,3] as an expression tree: 1:2:3:[] is same as 1:(2:(3:[])) (: is right-associative) [1,2,3] is another shorthand for 1:(2:(3:[])) The rst element of a nonempty list is the head : head [1,2,3] = 1 The list of the remaining elements is the tail tail [1,2,3] = [2,3] Underneath, there is a linked data structure (shown to the right) In conventional languages youd have to manage the links yourselves. Functional programming systems handle them automatically
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 42 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 43

cons 1 : 1 2 3 : : cons 2

cons 3 [] nil

Some List Functions


Haskell has many builtin functions on lists. (See Ch. 23 in the book.) Lets look at some and try to program them, as an exercise length xs, computes the length of the list xs length [a,b,c] = 3 take n xs, returns list of rst n elements from the list xs take 2 [a,b,c] = [a,b] sum xs, sums all the numbers in xs sum [1,2,3] = 6 (Solutions on next slide)
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 44

length [] = 0 length (x:xs) = 1 + length xs take 0 xs = [] take n [] = error "taking too many elements" take n (x:xs) = x : take (n-1) xs sum [] = 0 sum (x:xs) = x + sum xs Note the pattern-matching! The pattern (x:xs) matches any list that is constructed with a cons x gets bound to the head, and xs to the tail
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 45

An Observation on sum
sum basically replaces : with + and then calculates the result We have: sum [1,2,3] = sum 1:(2:(3:[])) = 1+(2+(3+0)) = 6 Note the similarity between tree for list 1:(2:(3:[])) and sum expression for 1+(2+(3+0)):
: : 1 2 3 [] : 1 2 3 0 + + +

This is a common pattern! Well get back to this when we treat higher-order functions Also: in a sense, data structures (like lists) in Haskell are just expressions where the operators (= constructors) cannot be calculated: thus, the constructors are left in the result (where they build the data structure)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

46

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

47

Tuples
Tuples are similar to records, or objects A tuple is like a container for data with a xed number of slots An example: (a,17,3.14159) This is a three-tuple whose rst component is a character, the second an integer, and the third a oating-point number It has the tuple type (Char,Integer,Float) Tuples can contain any type of data, for instance: (fac,(17,x)) :: (Integer -> Integer,(Integer,Char)) Thus, there are really innitely many tuple types
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 48

An Example of the Use of Tuples

Use tuples with two oats to represent 2D-vectors Dene functions vadd, vsub, vlen to add, subtract, and compute the length of vectors: vadd,vsub :: (Float,Float) -> (Float,Float) -> (Float,Float) vlen :: (Float,Float) -> Float (Solutions on next slide)

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

49

Some More on Recursion and Modularity of Programs


vadd (x1,y1) (x2,y2) = (x1+x2,y1+y2) vsub (x1,y1) (x2,y2) = (x1-x2,y1-y2) vlen (x,y) = sqrt (x**2 + y**2) Note the pattern-matching to get the components of the argument tuples A basic idea of functional programming is to dene small but general functions, than can be used as building blocks in many applications An example is the set of predened list functions in Haskell If you store your data with lists, then you can often use these functions to achieve what you want An example: say we want to sum the lengths of a number of vectors v1, . . . , vn Assume the vectors are stored in a list Well give two solutions to this on the next two slides
SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 50 SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17) 51

Direct Solution

A Solution that Reuses sum

A direct solution: sumvecs [] = 0 sumvecs (v:vs) = vlen v + sumvecs vs Note the similarity with sum Somehow were duplicating work here Lets try another solution where we use sum

Idea: rst create list of vector lengths, then sum the elements in this list sumvecs vs = let vlengths [] = [] vlengths (v:vs) = vlen v : vlengths vs in sum (vlengths vs) Note how we create the list of vector lengths by applying vlen to each element in the list of vectors This is a common pattern! More on this when we talk about higher-order functions

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

52

SoE Chapter 1: Problem Solving, Programming, and Calculation (revised 2007-08-17)

53

Modules and Data Types

Modules and Data Type Declarations


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007

Haskell code is packaged in modules A module contains a number of declarations The scope of the declarations is the module (normally not visible outside) Module = software component containing functions, data types, . . . Good for packaging libraries to be reused in other Haskell programs Declarations in a module are made visible in another module by an import declaration import Shape Typically one Haskell le one module

Modules and Data Type Declarations (revised 2007-08-17)

Modules and Data Type Declarations (revised 2007-08-17)

Syntax of modules: module XXX(...exported names...) where

A Haskell compiler needs a special module Main with a function main to create an executable program: module Main where

...declarations... ...declarations... main = .... main has a special I/O-data type, more on this later In Hugs you dont need the Main module, you just :load a module and then its exported declarations become visible

Modules and Data Type Declarations (revised 2007-08-17)

Modules and Data Type Declarations (revised 2007-08-17)

A Simple Module Example


A simple module Vector with our vector operations on tuples:
module Vector where vadd,vsub :: (Float,Float) -> (Float,Float) -> (Float,Float) vlen :: (Float,Float) -> Float vadd (x1,y1) (x2,y2) = (x1+x2,y1+y2) vsub (x1,y1) (x2,y2) = (x1-x2,y1-y2) vlen (x,y) = sqrt (x**2 + y**2)

Another module can now import the Vector module and use the operations:
module Main where import Vector v1 = (1,3) v2 = (3,2) main = print (vadd v1 v2)

Note: no list of exported names = all declared names are exported. A version exporting only vadd, vlen would look like this:
module Vector(vadd,vlen) where ....
Modules and Data Type Declarations (revised 2007-08-17) 4

(The print function generates an action that prints a value to stdout (typically screen).)

Modules and Data Type Declarations (revised 2007-08-17)

Data Type Declarations


We can write functions that use the Color values: In Haskell you can dene your own data types A rst, simple example:
data Color = Black | Blue | Green | Cyan | Red | Magenta | Yellow | White f :: Color -> Integer f Black = 17 f Blue = f Black + 2 ...

Here, Color is a type (Just like Bool, Integer, [Integer]) Black, Blue etc. are constructors (just like True, 17, []) The elements of Color are the values Black, Blue etc.

Pattern-matching works as usual on user-dened constructors. (User-dened types are no different from predened types!)

Modules and Data Type Declarations (revised 2007-08-17)

Modules and Data Type Declarations (revised 2007-08-17)

Example: Geometrical Shapes


The previous example was quite limited Haskell can do more than types with a small number of given elements We can for instance dene types whose elements are structured data (like tuples) Ill show an example from the book on next page Say we want to represent some kinds of geometrical shapes (Later, we may want to do things with them like computing their areas, or displaying them graphically, or composing them into more complex shapes) We want to represent rectangles, ellipses, right triangles (90 degree angle), and general polygons

Modules and Data Type Declarations (revised 2007-08-17)

Modules and Data Type Declarations (revised 2007-08-17)

Rectangles, ellipses, and right triangles are characterized by two numbers, and polygons by a number of 2D-coordinates:
(x4,y4) (x3,y3) s1 r2 s1 r1 s2 s2 (x5,y5) (x2,y2)

Heres the data type declaration:


data Shape = Rectangle Float Float | Ellipse Float Float | RtTriangle Float Float | Polygon [(Float,Float)] deriving Show

(x1,y1)

So, for instance, Rectangle 2.3 3.1 represents a rectangle with sides of length 2.3 and 3.1, respectively (deriving Show gives a default way to print values of type Shape. More on this later)

Modules and Data Type Declarations (revised 2007-08-17)

10

Modules and Data Type Declarations (revised 2007-08-17)

11

The constructors Rectangle etc. take arguments and build data structures containing these arguments
Rectangle 2.3 3.1 Ellipse 9.0 9.0 RtTriangle 5.1 9.0 (,) 3.5 4.0 4.5 (,) 6.1 (,) 9.0 Polygon : : : []

Type Synonyms

In Haskell, we can dene type synonyms A type synonym has the same information as the original type, but the type system differs between them This is useful since sometimes one uses the same data type to represent different things For instance, we use oating point numbers to represent both sides of rectangles and radii of ellipses If we use type synonyms, then the type system can catch errors where we use values in the wrong way
12 Modules and Data Type Declarations (revised 2007-08-17) 13

3.8

You can also think of them as unique tags:


Rectangle 2.3 3.1

So Rectangle 2.3 3.1 is basically the same as the tuple (2.3,3.1) plus a tag telling that this tuple represents a rectangle
Modules and Data Type Declarations (revised 2007-08-17)

Type synonym declarations for our geometrical shapes:


type Radius = Float type Side = Float type Vertex = (Float,Float)

Type synonyms are used just as ordinary types:


circle :: Radius -> Shape circle r = Ellipse r r square :: Side -> Shape square s = Rectangle s s

New denition of the Shape data type:


data Shape = Rectangle Side Side | Ellipse Radius Radius | RtTriangle Side Side | Polygon [Vertex] deriving Show

Declaring, say, square :: Float -> Shape would give a type error

Modules and Data Type Declarations (revised 2007-08-17)

14

Modules and Data Type Declarations (revised 2007-08-17)

15

Functions on Shapes
area can be dened case by case by pattern-matching on different constructors Easy cases rst:
area (Rectangle s1 s2) = s1*s2 area (RtTriangle s1 s2) = s1*s2/2 area (Ellipse r1 r2) = pi*r1*r2

Lets dene a function area :: Shape -> Float that computes the area of a shape Solution on the next few slides . . .

(Assuming pi is dened in the module were working in)

Modules and Data Type Declarations (revised 2007-08-17)

16

Modules and Data Type Declarations (revised 2007-08-17)

17

What about polygons? Three corners or more: compute it by cutting a triangle, computing its area, and adding to area of rest of polygon (which is also a convex polygon)
v4 v3

Solution: Assume for now a function triArea that compute the area of a triangle given its corners
area (Polygon (v1:v2:v3:vs)) = (triArea v1 v2 v3) + area (Polygon v1:v3:vs) area (Polygon _) = 0
v2

v5

v6

v1

Recursive function, must terminate since one corner removed for each cut

Modules and Data Type Declarations (revised 2007-08-17)

18

Modules and Data Type Declarations (revised 2007-08-17)

19

triArea is computed with Herons formula:


a

We have the vertices but not the length of the sides between them Assume for now a function distBetween that computes the distance between two vertices:
c

A=

1 s(s a)(s b)(s c), where s = (a + b + c) 2

triArea :: Vertex -> Vertex -> Vertex -> Float triArea v1 v2 v3 = let a = distBetween v1 v2 b = distBetween v2 v3 c = distBetween v3 v1 s = 0.5*(a+b+c) in sqrt(s*(s-a)*(s-b)*(s-c))

(This is classical geometry)


Modules and Data Type Declarations (revised 2007-08-17) 20 Modules and Data Type Declarations (revised 2007-08-17) 21

A Note on Programming Style


Finally,
distBetween :: Vertex -> Vertex -> Float distBetween (x1,y1) (x2,y2) = sqrt ((x1-x2)^2 + (y1-y2)^2)
(x2,y2)

In the polygon case, we used smaller functions (triArea, distBetween) to compute results needed to compute the whole area This is a style of programming supported well by functional programming languages like Haskell: dene (or use predened) small, general functions to successively compose the desired solution

|x1x2|

|y1y2|

(x1,y1)

Modules and Data Type Declarations (revised 2007-08-17)

22

Modules and Data Type Declarations (revised 2007-08-17)

23

Basic Input/Output in Haskell

Chapter 3: IO Actions (Simple Graphics)


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ September 8, 2003 We said functional programming is about calculating expressions Gives a simple way of interacting: type an expression, obtain the calculated result But often more complex ways of interaction are needed Haskell has a special kind of data called actions Actions can interact with the environment (like performing I/O) Actions can be sequenced, so they are performed in a certain order

SoE Chapter 3: IO Actions (Simple Graphics)

SoE Chapter 3: IO Actions (Simple Graphics)

A Graphical View of Actions


A Haskell function can compute a sequence of actions The main function is a sequence of actions. When computed the actions are executed in order Actions may produce values, which can be used by the subsequent actions in scope (think of getchar()in C) An action producing a value of type a has type IO a However, actions are not functions! IO a is not the same type as a. Actions can only be put in sequence, not called as functions
output from action, can be used by later actions in same scope System state System state System state

SoE Chapter 3: IO Actions (Simple Graphics)

SoE Chapter 3: IO Actions (Simple Graphics)

Actions
A simple Haskell program printing Hello world: Some functions returning actions: putChar :: Char -> IO () getChar :: IO Char putStr :: [Char] -> IO () getLine :: IO [Char] writes character to standard output reads character from standard input writes string to standard output reads a line from standard input
module Main where main = putStr "Hello world\n"

(Actions producing no useful value have type IO ()) Strings are simply lists of characters in Haskell ([Char] is also called String) Special syntax for strings: "Hello"
SoE Chapter 3: IO Actions (Simple Graphics)

[H,e,l,l,o]
4 SoE Chapter 3: IO Actions (Simple Graphics) 5

A Small Example
How to put actions in sequence:
do putStr "Hello world\n" putStr "I am here.\n"

Lets write an action echo that reads a character and echoes it to the screen: (See next slide for solution)

putStr "Hello world\n"

putStr "I am here.\n" () ()

Special keyword do denotes beginning of sequence The layout rule decides when an action is considered to follow in sequence (dont put it to the left of previous action)
SoE Chapter 3: IO Actions (Simple Graphics) 6 SoE Chapter 3: IO Actions (Simple Graphics) 7

Composed Actions and what they Return


echo :: IO ()

A sequence of actions is itself an action (a composed action)


echo = do c <- getChar putChar c

A composed action returns the returned value (if any) of its last action Example:
get2 = do getChar getChar

getChar has type IO Char, thus returns a Char In the code above, c is bound to the returned character echo is executed when called in main:
module Main where main = echo

action returns the last character read Use as usual:


do c <- get2 putChar c

SoE Chapter 3: IO Actions (Simple Graphics)

SoE Chapter 3: IO Actions (Simple Graphics)

How to Return Special Values

A Second Small Example

Sometimes we would like to have more control over the returned values Then use: return :: a -> IO a return x does nothing but return x An example: an action that reads a character and returns the upper-case version (toUpper :: Char -> Char converts characters to upper case):
getUpper = do c <- getChar return (toUpper c)
SoE Chapter 3: IO Actions (Simple Graphics) 10

A composed action echoloop that repeatedly reads characters, echoes them, and exits when a space is hit (See next slide for solution)

SoE Chapter 3: IO Actions (Simple Graphics)

11

We need some kind of loop to do this Lets use recursion!


echoloop :: IO () echoloop = do c <- getChar if c == then return () else do putChar c echoloop

Two things to note:


the use of recursion to get a looping effect returning the value ()

() is the single value of the unit type () (same name for type and value!) Used for values that are not important (like return values from actions that we dont care about) Think of the value () as the empty tuple, and the type () as the empty tuple type

SoE Chapter 3: IO Actions (Simple Graphics)

12

SoE Chapter 3: IO Actions (Simple Graphics)

13

File Handling Actions

A Third Small Example

writeFile :: FilePath -> String -> IO () FilePath synonym for String writeFile "testFile.txt" "Hello File System" readFile :: FilePath -> IO String

Read a string from standard input and write it to le testFile.txt:


do s <- getLine writeFile "testFile.txt" s

getLine

many other actions for le/system/user I/O, see Ch. 16 in the book
(Error handling: see Ch. 16 as well)

writeFile "testfile.txt" s s ()

SoE Chapter 3: IO Actions (Simple Graphics)

14

SoE Chapter 3: IO Actions (Simple Graphics)

15

Actions are Ordinary Data


Actions are just like any other data, can for instance be stored in data structures and moved around A list of actions:
actionList = [putStr "Hi\n", writeFile "file.txt" "Hello file", putStr "Ho Ho\n"]

A useful function that turns a list of actions into a do-sequence: sequence_ :: [IO a] -> IO () main = sequence_ actionList (sequence_ is denable in Haskell itself. See the book, p. 259) A good exercise is to dene it. It is not hard!

However, must be put into a do-sequence in order to get executed

SoE Chapter 3: IO Actions (Simple Graphics)

16

SoE Chapter 3: IO Actions (Simple Graphics)

17

A Fourth Small Example


PutChar :: Char -> IO () writes a single character Dene putStr in terms of PutChar First a function converting a list of characters into a list of PutChar actions:
putCharList :: String -> [IO ()] putCharList [] = [] putCharList (c:cs) = putChar c : putCharList cs

Simple Graphics

The book denes a module SimpleGraphics for handling a graphics window It contains a number of actions to open and close such windows, and to draw different kinds of graphics objects in it It is used in the graphics library that is built up in the book I will not cover it here, but you will use it in Lab 2. I recommend reading about it in Ch. 3.2

Then easy to dene putStr:


putStr s = sequence_ (putCharList s)

SoE Chapter 3: IO Actions (Simple Graphics)

18

SoE Chapter 3: IO Actions (Simple Graphics)

19

String Processing

A String Programming Example


String (or text) processing is important Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007 Conversions beween different formats: les, documents, XML, web/database, etc. I think functional programming is good for this kind of application We will look at a simple example here: how to break a text into a list of words, that can be used for various things like: counting the number of words in the text printing the text with a given maximal line length in characters (breaking lines when next word does not t in)
A String Programming Example (revised 2007-08-17)
A String Programming Example (revised 2007-08-17) 1

Strings

Breaking a String Into Words


Words are sequences of characters separated by one or more whitespace characters: space, newline, tab (In Haskell: , \n, \t) We want a function that converts a string into a list of its words:
string2words :: String -> [String]

Strings are simply lists of characters in Haskell [Char] is also called String Special syntax for strings: "Hello" = [H,e,l,l,o] This means all general list functions will work on strings Makes it easy to write program for string processing since Haskell has a rich set of useful list functions

For instance,
string2words "Allan tar kakan i 28000 baud" => ["Allan","tar","kakan","i","28000","baud"]
A String Programming Example (revised 2007-08-17) 3

A String Programming Example (revised 2007-08-17)

How code string2words? We need a mental model. This is a simple parsing problem, which can be solved by a nite automaton with two states:
start skipping whitespace nowhitespace char scanning word

Well use a variation of this pattern: in each state we will look ahead and count the number of characters before changing to the other state: whitespace: count characters until non-whitespace char, then drop that number of characters and call the other function on rest of list word: count characters until whitespace char, then save that number of characters into string and call the other function on rest of list We can then use the standard function drop to skip a number of characters:
drop 3 [1,4,2,5,6] = [5,6]

whitespace char

whitespace char

nowhitespace char

Common design pattern: one function per state. When new character read the function for the new state is called
A String Programming Example (revised 2007-08-17) 4

(drop n s returns the list remaining after take n s)


A String Programming Example (revised 2007-08-17) 5

A First Solution
Functions string2words and string2words1 corresponding to states skipping whitespace and scanning word, respectively:
string2words [] = [] string2words s = string2words1 (drop (find_nows s) s) string2words1 [] = [] string2words1 s = let n = (find_ws s) in take n s : string2words (drop n s)

Functions to count characters until next whitespace and next no-whitespace, respectively:
find_ws [] = 0 find_ws (c:cs) = if c == || c == \n || then 0 else 1 + find_ws cs c == \t

find_nows [] = 0 find_nows (c:cs) = if c \= && c \= \n && c \= \t then 0 else 1 + find_nows cs

Note how the words are collected into separate strings by take Also note that : in string2words1 puts the string as element into the list, so the returned list is a list of strings (not characters)

A String Programming Example (revised 2007-08-17)

A String Programming Example (revised 2007-08-17)

A More Elegant Slution

A More General Character Count Function

This solution works ne, but is a bit clumsy In particular, find_ws and find_nows are very similar They do precisely the same, but with negated conditions! Can we factor out the common structure? Yes, if we can make the condition a parameter to a more general function! Lets see on next slide how to do this . . .

Haskell has higher order functions We can thus dene a function find that takes a predicate p on characters as rst arguments and counts the number of characters up to the rst character c such that p c == True:
find :: (Char -> Bool) -> String -> Integer find p [] = 0 find p (x:xs) = if p x then 0 else 1 + find p xs

A String Programming Example (revised 2007-08-17)

A String Programming Example (revised 2007-08-17)

Predicate to check for whitespace:


ws :: Char -> Bool ws ws ws ws \n \t _ = = = = True True True False

Then simply:
find_ws s = find ws s

For find_nows, we must have a negated whitespace-predicate:


not_ws c = not (ws c)

We get:
find_nows s = find not_ws s

A String Programming Example (revised 2007-08-17)

10

A String Programming Example (revised 2007-08-17)

11

Final Solution
module String2words where ws ws ws ws \n \t _ = = = = True True True False

Applications of string2words

Lets do the two applications mentioned before: counting the number of words in the text printing the text with a given maximal line length in characters (breaking lines when next word does not t in) The rst you can do yourself in one line! The second is more interesting . . .

find p [] = 0 find p (x:xs) = if p x then 0 else 1 + find p xs find_ws s = find ws s find_nows s = find (not_ws) s string2words [] = [] string2words s = string2words1 (drop (find_nows s) s) string2words1 [] = [] string2words1 s = let n = (find_ws s) in take n s : string2words (drop n s)

A String Programming Example (revised 2007-08-17)

12

A String Programming Example (revised 2007-08-17)

13

The Solution
A function words2lines linelen ws, where linelen is the line length and ws is a list of words to be printed Idea: keep a current position on the line, check length of next word, if greater than linelen then start new line else output word on current line and update position Current position passed as argument Local function to do this, so words2lines does not need to have this extra argument We will use the append operation ++ on lists: [1,2,3] ++ [4,2] = [1,2,3,4,2]
A String Programming Example (revised 2007-08-17) 14

words2lines linelen ws = let w2l [] pos = [] w2l (w:ws) pos = if pos + length w < linelen then w ++ [ ] ++ w2l ws (pos + length w + 1) else \n : w ++ [ ] ++ w2l ws (length w + 1) in w2l ws 0

Not perfect. Leaves space at end of each line. Somewhat poor treatment of words longer than line length always new line even if the long word is rst in list Exercise: write a new solution that handles these cases better
A String Programming Example (revised 2007-08-17) 15

List Functions

List Functions, Polymorphic Functions, and Higher-Order Functions


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ September 10, 2003

We have seen some list functions already There are some important ones left Well dene append (++) and zip here

List Functions, Polymorphic Functions, and Higher-Order Functions

List Functions, Polymorphic Functions, and Higher-Order Functions

Append
(Weve seen it in use before) Heres the denition:
[] ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys)

zip

zip takes two lists and returns a list of pairs of their respective elements (like closing a zipper):
zip :: [a] -> [b] -> [(a,b)] zip (a:as) (b:bs) = (a,b):zip as bs zip _ _ = []

Thus,
[1,2] ++ [3,4,5] = => => => = 1 : 2 : [] ++ 3 : 4 : 5 : [] 1 : (2 : [] ++ 3 : 4 : 5 : []) 1 : 2 : ([] ++ 3 : 4 : 5 : []) 1 : 2 : 3 : 4 : 5 : [] [1,2,3,4,5]

Thus,
zip [1,2,3] ["allan","tar","kakan"] => [(1,"allan"),(2,"tar"),(3,"kakan")]

Note that append takes time proportional to length of rst argument


List Functions, Polymorphic Functions, and Higher-Order Functions 2

So we can for instance use zip to put a number on each element in a list
List Functions, Polymorphic Functions, and Higher-Order Functions 3

Polymorphic types
[a] -> Integer is the most general type of length Consider the following function (that computes the length of a list):
length [] = 0 length (x:xs) = 1 + length xs

Any other possible type for length can be obtained by replacing a with some other type Haskells type system gives the most general type, unless you give an explicit type declaration Type inference is used to nd this type

What is the type of length? It could be [Integer] -> Integer, or[Char] -> Integer, or even [[Integer]] -> Integer! length should really work regardless of the type of the elements It has type [a] -> Integer, where a is a type variable This is a polymorphic type
List Functions, Polymorphic Functions, and Higher-Order Functions 4

List Functions, Polymorphic Functions, and Higher-Order Functions

Higher-Order Functions
Some other polymorphic list functions (and lists):
head tail take drop (++) zip (:) [] :: :: :: :: :: :: :: :: [a] -> a [a] -> [a] Integer -> [a] -> [a] Integer -> [a] -> [a] [a] -> [a] -> [a] [a] -> [b] -> [(a,b)] a -> [a] -> [a] [a]

Haskell is a higher order language This means that functions are data just as data of any other ordinary type They can be stored in data structures, passed as arguments, and returned as function values Functions as arguments provides a way to parameterize function denitions, where common computational structure can be factored out Functions that take functions as arguments are called Higher-Order Functions Common computational patterns can be captured as higher order functions Well show some important examples here

List Functions, Polymorphic Functions, and Higher-Order Functions

List Functions, Polymorphic Functions, and Higher-Order Functions

A First Example: map


Computation pattern captured by a higher-order function map: We have previously seen (in Chapter 3.1):
putCharList :: String -> [IO ()] putCharList [] = [] putCharList (c:cs) = putChar c : putCharList cs map f [] = [] map f (x:xs) = f x : map f xs

map applies an arbitrary function f to the elements in a list


map :: (a -> b) -> [a] -> [b]

This is a common pattern: to apply a function to each element in a list Note that the type of map is polymorphic, this is common for higher-order functions We can now dene
putCharList cs = map putChar cs
List Functions, Polymorphic Functions, and Higher-Order Functions 8 List Functions, Polymorphic Functions, and Higher-Order Functions 9

A Second Example: lter

Some Syntax: Guarded Denitions


This is really how filter is dened in Haskell:
filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) | p x = x : filter p xs | otherwise = filter p xs

filter removes all elements from a list that do not satisfy a given predicate:
filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) = if p x then x : filter p xs else filter p xs

This denition uses guards: conditions that lter out different cases They are tried in order (like pattern-matching) otherwise is a catchall, often used at end Guards are just syntactic sugar, can always be expressed with if-then-else
10 List Functions, Polymorphic Functions, and Higher-Order Functions 11

For instance: if even returns True for exactly the even numbers, then
filter even [0,1,2,3,4,5] => [0,2,4]

List Functions, Polymorphic Functions, and Higher-Order Functions

Folds
Now consider multiplying the numbers in a list: Rather than applying a function to each single member of a list, we might want to apply a function with two arguments successively to all elements An instance of this is summing all numbers in a numeric list, recall sum:
sum [] = 0 sum (x:xs) = x + sum xs product [] = 1 product (x:xs) = x * product xs

Or, ANDing together a list of booleans:


and [] = True and (x:xs) = x && and xs

Applies successively to all elements, collecting them into their sum

Theres something in common here!

List Functions, Polymorphic Functions, and Higher-Order Functions

12

List Functions, Polymorphic Functions, and Higher-Order Functions

13

Haskell actually denes two folds: All these functions are instances of fold:
fold :: (a -> b -> b) -> b -> [a] -> b fold op init [] = init fold op init (x:xs) = x op (fold op init xs)

foldr: same as fold foldl, dened as:


foldl :: (b -> a -> b) -> b -> [a] -> b foldl op init [] = init foldl op init (x:xs) = foldl op (init op x) xs

We can now dene:


sum xs = fold (+) 0 xs product xs = fold (*) 1 xs and xs = fold (&&) True xs

foldr foldl

fold from the right fold from the left

Can you think of any other functions that can be dened with fold?

Note the accumulating argument for foldl, where the sum is collected

List Functions, Polymorphic Functions, and Higher-Order Functions

14

List Functions, Polymorphic Functions, and Higher-Order Functions

15

Why two Folds?

How do the Folds Work?


Lets compare the evaluation of foldr (+) 0 [1,2,3] and foldl (+) 0 [1,2,3]:
foldr (+) 0 [1,2,3] => => => => => foldl (+) 0 [1,2,3] => => => => => 1 1 1 1 6 + + + + foldr (+) 0 [2,3] (2 + foldr (+) 0 [3]) (2 + (3 + foldr (+) 0 [])) (2 + (3 + 0))

Why two folds? Sometimes, one can be more efcient than the other (see Ch. 5.4.2) Also, they have slightly different types, there are cases where one will work but not the other However, under some conditions they will compute the same answer (more on this in Ch. 11.3)

foldl foldl foldl (((0+ 6

(+) (0 + 1) [2,3] (+) ((0 + 1) + 2) [3] (+) (((0 + 1) + 2) + 3) [] 1) + 2) + 3)

List Functions, Polymorphic Functions, and Higher-Order Functions

16

List Functions, Polymorphic Functions, and Higher-Order Functions

17

Note how foldl and foldr builds the expression tree in different ways:
foldl
+ + + 0 1 2 1 3 2 3 + 0 +

foldr
+

Since + is associative these give the same result If the operator is not associative, then foldl and foldr can yield different results
List Functions, Polymorphic Functions, and Higher-Order Functions 18

Lazy Evaluation and Innite Lists

Lazy Evaluation, and More on List Notation


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ October 13, 2004 Most languages have eager evaluation of function arguments (call by value) That is: evaluate all arguments in full before a call is made Haskell uses lazy evaluation (call by need) This means: delay evaluation of anything until it is needed (Never do today what you can postpone until tomorrow )

Lazy Evaluation (revised 2004-10-12)

Lazy Evaluation (revised 2004-10-12)

Lazy evaluation can change the meaning of programs:


inf = inf f x y = if x == 0 then 1 else y

Lazy evaluation can save work, but is costly to implement (more complex evaluation mechanism) Its great advantage is that it can be used with potentially innite data structures This enables a different style of programming, with cleaner control

In language with eager evaluation: f 0 inf In Haskell:


f 0 inf => if 0 == 0 then 1 else inf => if True then 1 else inf => 1

(it does not terminate)

Lazy Evaluation (revised 2004-10-12)

Lazy Evaluation (revised 2004-10-12)

How Does it Work?


Consider
ones = 1:ones

Try to print it! Nonterminating, however its value is not Rather, innite list of ones However, if we only need a nite part of it, only that part is computed. For instance, if we only need the rst ve elements: take 5 ones [1,1,1,1,1] (no lack of information here)

Consider again take 5 ones:


take 5 ones take 5 (1:ones) 1:(take 4 ones) 1:(take 4 (1:ones)) 1:1:(take 3 ones) 1:1:(take 3 (1:ones)) 1:1:1:(take 2 ones) 1:1:1:(take 2 (1:ones)) 1:1:1:1:(take 1 ones) 1:1:1:1:(take 1 (1:ones)) 1:1:1:1:1:(take 0 ones) 1:1:1:1:1:[] [1,1,1,1,1]
5

Lazy Evaluation (revised 2004-10-12)

Lazy Evaluation (revised 2004-10-12)

An Example: Line Numbering

Some Help Functions

Lets see how we can put line numbers on each line in a text Assume the text is formatted as a list of lines (each line a string) Design:

A way to compute the innite list of positive integers:


posints = let posints1 n = n : posints1 (n+1) in posints1 1

A function that converts a pair (integer,string) into a string:

for each line, make a pair of line number and line then convert into string (with number as text in front)

pair2string (i,s) = show i ++ ". " ++ s

(show converts values into printable strings)

Lazy Evaluation (revised 2004-10-12)

Lazy Evaluation (revised 2004-10-12)

The Solution

Convenient List Notations


Haskell has a number of convenient list notations:

We use higher order functions to produce a short solution:


number_lines s = map pair2string (zip posints s)

[m,m+step..n] is shorthand for [m,m+step,m+2*step,...,n] E.g., [1,3..7] [1,3,5,7]

Note that zip returns a list as long as its shortest argument. Thus, only the initial segment of posints with the same length as s is used zip produces a list of pairs, then trivial to map the conversion function over its elements

If the step is one it can be omitted: [1..5] [1,2,3,4,5]

Omitted upper limit means innite list: [1..] [1,2,3,...]

Thus, our line numbering function can be rewritten as


number_lines s = map pair2string (zip [1..] s)
Lazy Evaluation (revised 2004-10-12) 8 Lazy Evaluation (revised 2004-10-12) 9

List Comprehensions
Sometimes one wants to generate lists whose elements are functions of elements of other lists List Comprehensions provide a convenient notation for this Example:
[(x,y) | x <- [0,1,2], y <- [a,b]] => [(0,a),(0,b),(1,a),(1,b),(2,a),(2,b)]

An Example
A classical sorting algorithm: quicksort Idea:

Here, x <- [0,1,2] and y <- [a,b] are called generators They generate indices (x, y above), much like in a nested loop It is also possible to have a guard a condition ltering the list:
[(x,y) | x <- [0,1,2], y <- [1,2], x < y] => [(0,1),(0,2),(1,2)]
Lazy Evaluation (revised 2004-10-12) 10

select an element (say, the rst) move all smaller elements to the left move all greater (or equal) elements to the right apply quicksort recursively to the moved sequences

(Solution on next slide)


Lazy Evaluation (revised 2004-10-12) 11

Quicksort in Haskell, with list comprehensions:


qsort [] = [] qsort (x:xs) = qsort [y | y <- xs, y < x] ++ [x] ++ qsort [y | y <- xs, y >= x]

Lazy Evaluation (revised 2004-10-12)

12

Recursive Data Types

Chapter 7: Trees (and Recursive Data Types)


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ September 2, 2004

So far, we have dened data types with a number of cases, each of xed size How do we dene data types for data like lists, which can have an arbitrary number of elements? By making the data type denition recursive:
data IntList = Nil | MkIntList Int IntList

IntList can be either Nil, or a data structure that contains an Int and an IntList Note similarity between data type declaration and context-free grammar

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

Polymorphism
Some IntList examples: Haskells own data type for list is polymorphic
Nil MkIntList 4 Nil MkIntList 3 MkIntList 7 MkIntList 9 Nil

We can roll our own polymorphic list data type:


data List a = Nil | MkList a (List a)

This data type is precisely the same as Haskells list data type, except that the constructor names are different! Data type declarations can be recursive and polymorphic Haskells built-in data types can in principle be declared in the language itself

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

Data Types for Trees


We can easily make our own data types for trees, like:
data Tree a = Leaf a | Branch (Tree a) (Tree a)

Operations on Trees

Let us dene some useful operations over our trees:


a map for trees, that applies a function to all data stored in a tree, a function to put the elements in a tree into a list,
Branch

A data type for trees with data stored in the leaves


Leaf c Branch Branch Leaf 3 Leaf 17 Leaf [1,2] Branch Branch Leaf []

a function to compute the size (number of leaves) of a tree, and


Leaf [2..]

Leaf 3

Leaf [3,3,3]

Many other variations possible, see examples in the book Let us use this type for now
SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02) 4

a function to compute the height of a tree.

(Code on next two slides)


SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02) 5

Map on trees:
mapTree :: (a -> b) -> Tree a -> Tree b mapTree (Leaf x) = Leaf (f x) mapTree (Branch t1 t2) = Branch (mapTree f t1) (mapTree f t2)

Size (number of leaves):


treeSize :: Tree a -> Integer treeSize (Leaf x) = 1 treeSize (Branch t1 t2) = treeSize t1 + treeSize t2

(Hmmm, quite similar to map on lists, right? Is there some common underlying structure here? In the eld of generic programming, such connections are investigated.) To put the elements in a tree into a list:
fringe :: Tree a -> [a] fringe (Leaf x) = [x] fringe (Branch t1 t2) = fringe t1 ++ fringe t2
SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02) 6

Height:
treeHeight :: Tree a -> Integer treeHeight (Leaf x) = 0 treeHeight (Branch t1 t2) = 1 + max (treeHeight t1) (treeHeight t2)

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

A Different Example: Arithmetic Expressions


Arithmetic expressions are really trees:
+ (3/2) + (1*5) 3 / 2 1 * 5 (3/2) + (1*5) 3 / 2 1 + * 5 C3 Div C2 Add Mul C1 C5

data Expr = C Float | Add Expr Expr | Sub Expr Expr | Mul Expr Expr | Div Expr Expr

Each tree now represents an arithmetic expression:

Let us dene a data type for arithmetic (oating-point) expressions! We can then use it for various symbolic manipulations of such expressions (Data type declaration on next slide)

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

Evaluating Expressions
An alternative data type declaration:
data Expr = C Float | Expr :+ Expr | Expr :- Expr | Expr :* Expr | Expr :/ Expr

One operation is to evaluate expressions


eval eval eval eval eval eval :: Expr -> (C x) = x (e1 :+ e2) (e1 :- e2) (e1 :* e2) (e1 :/ e2) Float = = = = eval eval eval eval e1 e1 e1 e1 + * / eval eval eval eval e2 e2 e2 e2

Demonstrates inx constructors such must begin with : (canonical example is cons) So

is represented by (C 3 :/ C 2) :+ (C 1 :* C 5)

eval ((C 17) :+ ((C 3) :- (C 1))

19.0

eval is a simple interpreter for our expression trees

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

10

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

11

Exercise (mini-project): extend Expr with variables. Then dene a small symbolic algebra package for manipulating and simplifying expressions, for instance:
evaluate constant subexpressions simplify as far as possible using algebraic identities symbolic derivation etc

SoE Chapter 7: Trees (and Recursive Data Types) (revised 2004-09-02)

12

Currying (what Functions of Several Arguments Really are)

Chapter 9: More About Higher-Order Functions


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007 Remember simple? A function of three variables, we said:
simple :: Integer -> Integer -> Integer -> Integer simple x y z = x*(y + z)

But in Haskell, a function only takes one argument ! Whats up?

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

simple x y z means ((simple x) y) z (function application is left associative) Integer -> Integer -> Integer -> Integer means Integer -> (Integer -> (Integer -> Integer)) Thus, simple is a function in one argument, returning a function of type Integer -> (Integer -> Integer) which returns a function of type Integer -> Integer which returns an Integer! Encoding functions with several arguments like this is called currying (after Haskell B. Curry, early logician)
SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 2 SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 3

We could have dened:


simple :: (Integer,Integer,Integer) -> Integer simple (x,y,z) = x*(y + z)

Another way to represent a function of three arguments, as a function taking a 3-tuple But it is not the same function it has different type! This version may seem more natural, but the curried form has some advantages

Currying and Syntactical Brevity


A declaration What is simple 5? A function in two variables (say x, y), that returns 5*(x + y) We can use simple 5 in every place where a function of type Integer -> (Integer -> Integer) can be used f x = g x

Direct Function Declarations

where g does not contain x, can be written f = g The function f equals the function g, not stranger than scalar declarations like pi = 3.154159

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

A First Example
Recall sum (and all the other functions dened by folds):
sum xs = foldl (+) 0 xs

A Second Example

A function that reverses a list We rst make a recursive denition, then redo it using higher order functions, and nally we make it as terse as possible (Recursive solution on next slide)

Same as
sum xs = (foldl (+) 0) xs

Both sum and foldl have xs as last argument (and nowhere else) It can then be cancelled:
sum = foldl (+) 0

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

Recursive reverse

Higher-Order reverse
The main operation of reverse is to put an element in a list, which is accumulated in an argument Can we dene a binary operation and use, say, foldl to dene reverse (or rev1)? Lets line up their denitions:
rev1 acc [] = acc rev1 acc (x:xs) = rev1 (x:acc) xs foldl op init [] = init foldl op init (x:xs) = foldl op (init op x) xs

We use the stack the books principle:


reverse xs = rev1 [] xs where rev1 acc [] = acc rev1 acc (x:xs) = rev1 (x:acc) xs

(Try it on a few arguments to see how it works!) Note where, an alternative to let when making local denitions. Some subtle differences but mostly interchangeable with let

Hmmm, an operation revOp such that acc revOp x = x:acc?


SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 8 SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 9

Heres the result:


reverse xs = foldl revOp [] xs where revOp acc x = x:acc

Can we proceed to break down the denition into smaller, more general building blocks? Consider revOp. It is really just a cons (:), but with switched arguments A general function that switches (or ips) arguments:
flip :: (a -> b -> c) -> (b -> a -> c) flip f x y = f y x

(So flip f is a function that performs f but with ipped arguments) Then
revOp acc x = flip (:) acc x
SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 10 SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 11

Nameless Functions
revOp acc x = flip (:) acc x

Can be simplied to
revOp = flip (:)

Functions dont have to be given names We can write nameless functions through -abstraction: \x -> e stands for function with formal argument x and function body e (Comes from -calculus, where we write x.e) \x -> x + 1, an increment-by-one function Can be used freely provided the type is OK map (\x -> x + 1) xs returns list with all elements incremented by one

Finally, we obtain
reverse = foldl (flip (:)) []

Simple? Obfuscated? Its much a matter of training to appreciate this style

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

12

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

13

Sections
Syntactical conveniences: \x y -> e shorthand for \x -> (\y -> e) Pattern matching as in ordinary denitions, like \(x,y) -> x + y Currying can be dened through -abstraction: simple 5 = \x y -> simple 5 x y Also note: f x = .... is precisely the same as f = \x -> (....)
SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 14 SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17) 15

Sections generalize curried syntax to binary operators Really just syntactic sugar, but quite convenient. . . Using + as example: (x+) same as \y -> x+y (+y) same as \x -> x+y (+) same as \x y -> x+y

Function Composition
Example:
posInts :: [Integer] -> [Bool] posInts xs = map test xs where test x = x > 0

A well-known operation in mathematics, there dened thus:


(f g )(x) = f (g (x)),
for all x

can be written
posInts xs = map (> 0) xs

Haskell denition:
(.) :: (b -> c) -> (a -> b) -> a -> c (f . g) x = f (g x)

or even, through curry-cancelling


posInts = map (> 0)

Think of pipes in unix: unix command function producing stream of characters, pipe between commands function composition. Or functions as boxes:
g f f . g

Very concise! Easy to understand? You judge.

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

16

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

17

A simple example: Function converting string with newlines to list of lines (through Standard Prelude function lines :: String -> [String]), then computing the lengths of each line:
(map length) . lines

(A good exercise is to write lines yourself, and try to reuse as much as possible from string2words)

SoE Chapter 9: More About Higher-Order Functions (revised 2007-08-17)

18

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions)
Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007
SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2

We have dened shapes, data representations for simple geometrical objects (no position information, no colour information) You have also tried the Graphics Library for graphics windows actions The book denes two more data types for graphics objects: Regions, adds information for positioning and scaling + set operations Pictures, adds colour information for regions + composition of several regions into 2D-scenes Overview given here (including refresh of shapes and graphics windows)
SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 1

Graphics Windows

A Graphics Windows Example

Actions to handle a graphics windows (open, close etc.) and draw Graphic values in it They all use a window handle of type Window to identify the window where the action should go Graphic is a data type for low-level representations of graphics objects Need not be concerned with the details of Graphic here Will build on this by mapping the other data types into Graphic

main0 = runGraphics ( do w <- openWindow "My First Graphics Program" (300,300) drawInWindow w (text (100,200) "Hello Graphics World") k <- getKey w closeWindow w )

(text :: Point -> String -> Graphic creates graphic value for text) getKey :: Window -> IO Char reads keystrokes

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

Shapes
Regions extend shapes with: Recall the Shape data type:
type Radius = Float type Side = Float type Vertex = (Float,Float) data Shape = Rectangle Side Side | Ellipse Radius Radius | RtTriangle Side Side | Polygon [Vertex] deriving Show

Regions

set operations (union, intersection, complement, empy set), and scaling and translation Furthermore: translation function into Graphics (so regions can be drawn), and predicate checking if a coordinate belongs to a region (good for user interaction with regions) Wrapped in module Region
4 SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 5

Well see how to use shapes as elements in regions and pictures


SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

The Region Data Type


data Region = | | | | | | deriving Shape Shape -- primitive shape Translate Vector Region -- translated region Scale Vector Region -- scaled region Complement Region -- inverse of region Region Union Region -- union of regions Region Intersect Region -- intersection of regions Empty -- empty region Show

An Example

let c = Shape (Ellipse 0.5 0.5) s = Shape (Rectangle 1 1) in (Scale (2,2) c) Union (Translate (1,0) s) Union (Translate (-1,0) s)
y

type Vector = (Float,Float)

Constructor and type names can be same OK to use backquotes for constructors just as for functions
SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 6 SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 7

Another Example
oneCircle = Shape (Ellipse 1 1) manyCircles = [Translate (x,0) oneCircle | x <- [0,2..]] fiveCircles = foldr Union Empty (take 5 manyCirles)

The Meaning of Shapes and Regions


What does a shape, or a region mean? They represent sets of points in space For an ellipse with radii r1 and r2: { (x, y ) |
x

x r1

+
y

y r2

1}

r2 r1

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

A set can be represented by its characteristic function: a predicate telling whether a point is in the set or not We dene translations from shapes and regions to characteristic functions:
containsS :: Shape -> Coordinate -> Bool containsR :: Region -> Coordinate -> Bool

More interesting to use containsS and containsR to test if coordinates belong to a shape (or region) or not Can be used to test in which shape (region) a mouse click hits This is useful for interactive applications We will not dene the characteristic functions here, see the book Ch. 8 for details

The characteristic function can give an implementation (two-color graphics): create array (matrix) of pixels test each pixel, set on/off depending on function Transfer array to graphics memory In practice too heavy though, better to use other graphics interfaces
SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 10

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

11

Pictures

The Picture Module

Regions represent sets of points Each Region, when given a colour, can be seen as a graphical object Pictures are formed from different graphical objects Well check out the Picture module, the Picture data type, how to draw Pictures (briey) and an interesting application (to move objects to front of picture by mouse clicks)

module Picture (...lots of stuff..., module Region ) where import Draw import Region import SOEGraphics hiding (Region) import qualified SOEGraphics as G (Region)

Whats this hiding and qualified stuff?

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

12

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

13

The Picture Data Type


SOEGraphics also contains a data type Region Name clash with our own Region We can import all of SOEGraphics except Region using hiding Still want access to the Region of SOEGraphics, but under different name import qualified statement gives this under name G.Region
data Picture = Region Color Region -- Put colours on Regions | Picture Over Picture -- Must know which is over -- if overlap | EmptyPic -- Empty picture deriving Show

Color dened as before:


data Color = Black | Blue | Green | Cyan | Red | Magenta | Yellow | White

Region Red (Shape (Ellipse 10 10)): a red circle with radius 10

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

14

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

15

Drawing Pictures

Drawing Regions

First pictures, then regions (top-down approach) Assume for now


drawRegionInWindow :: Window -> Color -> Region -> IO ()

How to draw regions (function drawRegionInWindow)? Well not give the full denition here (see the book Ch. 10), but rather a very brief overview Simple shapes are easy, using predened low-level primitives Scaling, translation is easy (if the translated/scaled region is), but needs some consideration do obtain efcient solution Union is easy (just draw the regions in any order) But what about intersection? Complement?

Its dened in the book, we will not give the details here. Then
drawPic drawPic drawPic drawPic :: Window -> Picture -> IO () w (Region c r) = drawRegionInWindow w c r w (p1 Over p2) = do drawPic w p2; drawPic w p1 w EmptyPic = return ()

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

16

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

17

A Simple Example
Intersection and complement are best computed pixel-by-pixel, with pixel sets represented by arrays We could do it in Haskell, but would be inefcient SOEGraphics has type Region for pixel arrays (using existing OS primitives and representations) Will use this data type (renamed to G.Region) G.Region provides operations to create graphics objects (rectangles, ellipses, polygons) and set operations on these (and, or, xor, set difference)

A function to draw a picture and close window when the space key is hit:
draw :: String -> Picture -> IO () draw s p = runGraphics ( do w <- openWindow s (xWin,yWin) drawPic w p spaceClose w )

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

18

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

19

User Interaction

Move Regions to Top


A function for moving regions to the top by clicking on them We can know the position of a mouse click (through an IO action returning the coordinates) Idea: 1. Given a Picture, put its regions into a list sorted with the uppermost regions rst 2. Go through the list to nd the rst region that is hit by the mouse click (getLBP :: IO Coordinate) 3. if there is such a region, then return the list where this region is moved to top, and redraw the image 4. otherwise do nothing
20 SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17) 21

It is interesting not only to draw pictures, but also to manipulate them This requires some kind of interaction: Capture mouse clicks and cursor positions Calculate which region is being marked Perform appropriate action on data structure Update screen accordingly
SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

A function adjust to move the hit region rst Creating a list of regions from a Picture: We must distinguish the case when a region is hit and when no region is
picToList picToList picToList picToList :: Picture -> [(Color,Region)] EmptyPic = [] (Region c r) = [(c,r)] (p1 Over p2) = picToList p1 ++ picToList p2

Use the Maybe data type for this (dened in Standard Prelude):
Maybe a = Nothing | Just a

Note similarity with fringe How do we know that we get the list of regions in the right order? Think about it!

adjust uses standard prelude function break :: (a -> Bool) -> [a] -> ([a],[a]) which splits a list in two, at the rst element where the predicate becomes true (If no such element, then rst list = input list and second list = []) E.g. break odd [2,4,3,4,5] = ([2,4],[3,4,5]) (See Ch. 23 for a denition of break)

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

22

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

23

A loop function that draws the list of regions, waits for mouse click, adjusts the list of regions, and repeats (if click not in any region, then exit loop):
adjust :: [(Color,Region)] -> Coordinate -> (Maybe (Color, Region),[(Color,Region)]) adjust regs p = case (break (\(_,r)-> r containsR p) regs) of (top, hit:rest) -> (Just hit, top ++ rest) (_,[]) -> (Nothing, regs) loop :: Window -> [(Color, Region)] -> IO () loop w regs = do clearWindow w sequence_ [drawInWindow w c r | (c,r) <- reverse regs] (x,y) <- getLBP w case (adjust regs (pixelToInch (x - xWin2), pixelToInch (yWin2 - y)) of (Nothing,_) -> closeWindow w (Just hit, newRegs) -> loop w (hit : newRegs)

Note the case construct! It gives the possibility to choose alternatives on pattern-matching anywhere in the code, not just on function arguments

Note transformation of mouse coordinates from pixels to Region coordinates (clearWindow does what the name suggests)

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

24

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

25

Finally, a function draw2 that puts all together:


draw2 :: String -> Picture -> IO () draw2 s p = runGraphics ( do w <- openWindow s (xWin, yWin) loop w (picToList p) )

SoE Chapter 8, 10 (2, 3.2, 4): An Overview of the Graphics Library for Static Pictures (Shapes, Graphics, Regions) (revised 2007-08-17)

26

Induction

Chapter 11: Proof by Induction


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007 Have you ever performed proofs by induction? (You should have. . .) Then you know induction proofs are to prove properties that hold for all non-negative integers For instance, n.
n i=1 i

= n(n + 1)/2

Exercise: prove this property by induction!

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

Proofs by Induction for Properties of Natural Numbers


Goal: show that the property P is true for all natural numbers (whole numbers 0) Proof by induction goes like this: 1. Show that P holds for 0 2. Show, for all natural numbers n, that if P holds for n then P holds also for n+1 3. Conclude that P holds for all n Formulated in formal logic: [P (0) n.P (n) = P (n + 1)] = n.P (n)

Why does Induction over the Natural Numbers Work?


The set of natural numbers N is an inductively dened set (A variation of) Peanos axiom: 0N x.x N = s(x) N x.0 = s(x) x, y.x = y = s(x) = s(y ) s(x) successor to x, or x + 1 0 s(0) s(s(0)) s(s(s(0))) 0 1 2 3 Proofs by induction follow the structure of the inductively dened set!

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

The Inductively Dened Set of Lists

An Induction Principle for Lists

Inductively dened sets are typically sets of innitely many nite objects The set [a] of (nite) lists with elements of type a: [] [a] x a xs [a] = x:xs [a]

Proof by induction for nite lists goes like this: 1. Show that P holds for [] 2. Show, for all nite lists xs [a] and all possible list elements x a, that if P holds for xs then P holds also for x:xs 3. Conclude that P holds for all nite lists in [a] Formulated in formal logic:

Note similarity with the set of natural numbers!

[P ([]) x a, xs [a].P (xs) = P (x:xs)] = xs [a].P (xs)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

A Simple Example of Induction Over Lists


Note: a proof by induction holds only for nite lists Not for innite lists, or the divergent list () But very often this is good enough! At least, it is better than not knowing anything . . . :-) What induction hypothesis? General rule: look at the function denitions and try to formulate the induction hypothesis so it matches the recursive structure! Prove that length (xs ++ ys) = length xs + length ys for all nite lists xs, ys

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

A Number of Interesting Properties


Denitions of length and ++:
length [] = 0 length (x:xs) = 1 + length xs [] ++ ys = ys (x:xs) ++ ys = x:(xs ++ ys)

Some properties of map:


map id = id, where id = \x -> x map (f . g) = map f . map g map f . tail = tail . map f map f . reverse = reverse . map f map f (xs ++ ys) = map f xs ++ map f ys

Now formulate induction hypotheses and prove the result! Can we extend the proof to innite lists?

(More properties in book, p. 138)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

Another Proof by Induction


A property of fold: Let us prove map (f . g) = map f . map g! (Proof on wyteboard) if op is associative and if e is left and right unit element for op, then, for all nite xs: foldr op e xs = foldl op e xs One can use properties of this kind to develop programs by program transformations There is something called the Bird-Meertens formalism, which is a theory for functions over lists with many theorems like this

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

10

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

11

Let us prove a slightly simpler property: That sum xs = sum1 xs for all nite lists xs, where:
sum [] = 0 sum (x:xs) = x + sum xs sum1 xs = sum2 0 xs sum2 a [] = a sum2 a (x:xs) = sum2 (a+x) xs

Do you see how to generalize the proof to prove the property of foldl and foldr on the previous page?

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

12

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

13

Induction over Trees

Induction Principle for Trees

Trees are also inductively dened, e.g., the tree data type in Ch. 7:
data Tree a = Leaf a | Branch (Tree a) (Tree a)

1. Show, for any x a, that P holds for Leaf x 2. Show, for any two nite trees t1, t2 [a], that if P holds for t1 and t2 then P holds also for Branch t1 t2 3. Conclude that P holds for all nite trees in Tree a

Corresponding, inductively dened set of nite trees: for any x a, Leaf x Tree a t1, t2 Tree a = Branch t1 t2 Tree a

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

14

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

15

A Proof by Induction over Trees


A function f is strict if f = Let
f x = 17 g x = x + 1

Strictness

Show that length (fringe t) = treeSize t for all nite trees t, where
fringe (Leaf x) = [x] fringe (Branch t1 t2) = fringe t1 ++ fringe t2 treeSize (Leaf x) = 1 treeSize (Branch t1 t2) = treeSize t1 + treeSize t2

In Haskell, is f strict? g? Theorem: in a language with call-by-value, all user-dened functions are strict In a language with lazy evaluation, some user-dened functions can be non-strict

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

16

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

17

Strictness depends on whether the argument is needed or not Example: consider denition of && from Standard Prelude:
True && x = x False && _ = False

Some properties hold only for strict functions: Theorem: If f is strict, then f (if b then x else y) = if b then f x else f y Can you prove the theorem?

The rst argument must be evaluated to nd out whether it is True, thus && is strict in its rst argument But there are cases where the second argument is not needed, thus && is not strict in its second argument

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

18

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

19

A strict function in a lazy language can be evaluated with call-by-value! This is interesting, since call-by-value often is more efcient than lazy evaluation Strictness analysis is a program analysis that sometimes can detect if a function is strict Good compilers for lazy languages have strictness analyzers Is the following function strict or not?
f x = if x == 0 then 0 else x + f (x-1)

SoE Chapter 11: Proof by Induction (revised 2007-08-17)

20

Type Classes

Chapter 12: Type Classes and Qualied Types


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007 Haskell has more complex types than we have told you . . . (+) does not (only) have the type Integer -> Integer -> Integer It has type Num a => a -> a -> a Should be read for all types a that are members of Num, (+) has type a -> a -> a Num a is a type class Type class set of types

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

Integer is a member of Num a an instance So (+) :: Integer -> Integer -> Integer is still correct But also (+) :: Int -> Int -> Int (+) :: Float -> Float -> Float since Int and Float also are instances of Num

(Num a) => ... is a constraint on the type variable a Type constraints are propagated as part of the type inference Example:
double x = x + x

Here, we know (+) :: (Num a) => a -> a -> a Thus, we must have x :: (Num a) => a and x + x :: (Num a) => a It follows that double :: (Num a) => a -> a (since it takes x as argument and returns x + x)

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

Compare with object-oriented languages: These have classes, with subclasses and inheritance Objects of different classes can have methods with the same name, even if they do different things (since the objects are different) For instance a print method can print different things depending on the object and its class Thus, method names are overloaded the same name stands for different things in different contexts Same for operations like + in Haskell: means different things for Integer, Int, and Float In Haskell, a class is a collection of types + a number of method names, where each type has an implementation of each function in the class
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 4

Declarations

Class declarations declare new classes They declare the name of the class, possible subclass relations, and which methods the class has Instance declarations make types members of a class An instance declaration gives an implementation of each method for that particular type Haskell does have conveniences for default implementations of methods, more on this later

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

The Eq class
Eq: class for all types where the elements can be compared for equality Has two method names: == and /= Any type in Eq must provide implementations of these Which types are in Eq? Almost all of Haskells standard types! Excluded are function types, IO types, and types containing such types (like [a -> b]) (Can you nd some good reason why these are excluded?)
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 6 SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 7

So Eq-types are: Basic types (Integer, Char, Bool, Float, . . .) Types that are formed from Eq-types (like [Integer], [[Integer]], (Char,[Integer]), . . .)

Instance Declarations

Example 2: if a is a member of Eq,then [a] is Two lists are equal when:

Types are declared members of classes by instance declarations Contains denitions for the methods in the class Example 1: Eq-membership of Integer:
Instance Eq Integer where x == y = IntegerEq x y

They are both the empty list, or their heads and tails are equal In Haskell:
Instance Eq a => [] == [] = x:xs == y:ys = _ == _ = Eq [a] where True x == y && xs == ys False

(IntegerEq is a primitive operation comparing Integers) No instance declaration for /=, lets get back to this later

Note constraint on a Also note == being used on values of both types a and Eq a, not the same operation although same name!
8 SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 9

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

Instance Declarations of User-dened Types


Exactly the same as for builtin types! Example 3: Eq-membership of Tree a: Similar to lists, trees are equal if: They are both leaves, and contain the same element, or They are both non-leaves, their left subtrees are equal, and their right subtrees are equal In Haskell:
Instance Eq a => Eq (Tree a) where Leaf x == Leaf y = x == y Branch l1 r1 == Branch l2 r2 = l1 == l2 && r1 == r2 _ == _ = False
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 10

Class Declarations

Example: the class declaration for Eq:


Class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x == y) x == y = not (x /= y)

Denes class name, method names with type signatures, and possible default declarations of methods Default declarations are used if no explicit method denitions are given For Eq, it thus sufces to dene one of ==, /=
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 11

Inheritance
An instance declaration for [a]: Haskell has subclasses, with inheritance of methods A member of a subclass must also be a member of the superclass, and somehow dene its methods as well Example: Haskell has a predened class Ord for comparison operations. This class is a subclass to Eq. Declaration:
Class Eq a => Ord a where (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a Instance Ord a => Ord [a] where [] < x:xs = True x:xs < y:ys = x < y || (x == y && xs < ys) _ < _ = False ... etc ...

This yields lexicographic order (bokstavsordning) on lists Note subclass constraint necessary, since == is used

Note the constraint Eq a => ..., this gives the subclass relation
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 12 SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 13

Quicksort
Recall quicksort:
qsort [] = [] qsort (x:xs) = qsort [y | y <- xs, y < x] ++ [x] ++ qsort [y | y <- xs, y >= x]

A Selection of Haskells Standard Type Classes


The Show class Class for types with printable values These are essentially the same as Eq-types Most important function: show :: (Show a) => a -> String E.g. show [1,2,3] = "[1,2,3]" The actual methods in Show are more esoteric (for efency reasons), show dened in terms of these Usually one does not have to dene explicit instances of these methods, more on this later
14 SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 15

What type does it have? Only constraint on list elements is that we must be able to compare them Thus, qsort :: (Ord a) => [a] -> [a] This means it works on lists with elements of any comparable type!
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

Read

Num
Class for all numeric types (Integer, Int, Float, Double, . . .)

Class for types with readable values Inverse to Show Most important function: read :: (Read a) => String -> a E.g. read "[1,2,3]" = [1,2,3] Often convenient to use for Haskell programs with simple user interactions

class (Eq a, Show a) => Num a where (+),(-),(*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a

Notably no division (there are subclasses to Num with division) fromInteger is for overloading integer constants fromInteger 4 :: Float = 4.0

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

16

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

17

Coercion and fromInteger


Some languages have coercion of numerical types: For instance, if x :: Float and y :: Int then x+y :: Float, where a conversion from Int to Float is silently inserted for y Haskell does not have this kind of coercion The above would yield a type error However, fromInteger provides a kind of coercion for integer constants into different numeric types In Haskell, each integer constant n is parsed as fromInteger n Thus x + 17 means x + fromInteger 17, where fromInteger 17 will assume the type of x in the type inference process
SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17) 18

Exercise

Dene the type (Float,Float) as an instance of Num! (On the wyteboard only, I have no answer on next slide . . .) Can the instance declaration we will come up with be generalized to more general types of numerical pairs?

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

19

Haskells Standard Class Hierarchy (selection)


Eq
All except IO, (->)

Derived Instances
Haskell can derive default implementations for methods of the standard type classes Eq, Ord ,Enum, Bounded, Ix, Read, Show It then uses the natural way to dene method instances of the type class from the structure of the values in the instance type For instance, can automatically derive the implementation of methods in Eq for Tree a
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Eq

Show
All except IO, (->)

Read
All except IO, (->)

Ord
All except (->) IO, IOError

Num
Int, Integer, Float, Double

Bounded
Int, Char, Bool, () Ordering, tuples

Enum
(), Bool, Char, Ordering, Int, Integer, Float, Double

Real
Int, Integer, Float, Double

Fractional
Float, Double

Integral
Int, Integer

RealFrac
Float, Double

Floating
Float, Double

Monad
IO, [], Maybe

RealFloat
Float, Double

MonadPlus
IO, [], Maybe

Functor
IO, [], Maybe

Often very convenient! Uses underlying principles of generic programming

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

20

SoE Chapter 12: Type Classes and Qualied Types (revised 2007-08-17)

21

Animations

Chapter 13: A Module of Simple Animations


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ October 13, 2004 type Animation = ([Picture],Float) But this would tie us to a certain frequency. We would like to be more abstract, and leave the choice of frequency to the implementation
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 1

An animation is a time-varying image Implemented by a sequence of pictures (frames), that are shown by some time interval How to program animations, and represent them? We could use a list of Picture scenes, with some time interval:

Some Simple Examples


Thus, let us consider animations as functions of time! The implementation can then sample the function with suitable intervals For good reasons, we make the animation data type polymorphic: type Animation a = Time -> a type Time = Float Can then also use the programming model for sound, control signals, A Shape for a rubber ball that pulsates, and a Region for a rotating ball:
rubberBall :: Animation Shape rubberBall t = Ellipse (sin t) (cos t) revolvingBall :: Animation Region revolvingBall t = let ball = Shape (Ellipse 0.2 0.2) in Translate (sin t, cos t) ball

a general programming model for time-varying entities!

A Picture of a yellow ball revolving around a red pulsating ball:


planets :: Animation Picture planets t = let p1 = Region Red (Shape (rubberBall t)) p2 = Region Yellow (revolvingBall t) in p1 Over p2

Critical though, how to link the model to the real world

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

How to Animate (Real-world Connection)


A function
animate :: String -> Animation Graphic -> IO ()

How animate Works


Programmed in Haskell, uses some nonstandard, OS-specic libraries to access graphics and timers Basically a loop (a recursive action), which: 1. gets current time 2. draws animation (at current time) in window 3. waits for next clock tick (30 ms period) 4. loops to 1 Full denition at p. 169 in book
4 SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 5

that opens a window with a title and displays an animation in it Note the type Animation Graphic: must use conversion functions to change animation type from Picture, Region, or Shape:
shapeToGraphic :: Shape -> Graphic regionToGraphic :: Region -> Graphic picToGraphic :: Picture -> Graphic

Example: function anim to animate shapes


anim :: Animation Shape shapeToGraphic . anim :: Animation Graphic
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

Lifting Picture Operations to Animations


We may want to lift pictures into constant animations, like the empty picture:
emptyA :: Animation Picture emptyA t = EmptyPic

Type Classes for Lifting

Using the same name means overloading Type classes can be used for this! Two possible ways to use them:

Or dene a function that puts an animation on top of another:


overA :: Animation Picture -> Animation Picture -> Animation Picture overA a1 a2 t = a1 t Over a2 t

Make pre-existing operations work on animations: for instance, lift the Lift new operations from static values to animations by dening a new

numerical operations to numerical animations by making them instances of Num type class with methods for them (for instance methods empty, over for pictures and picture animations)
7

But it is cumbersome to introduce new names all the time! Would be nice to write a1 Over a2 also when a1, a2 are animations How do this?
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 6

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

Some technical issues: Animation a is just type synonym for Time -> a: these cannot be made instances of a class! (For some technical reasons) We can dene a new but similar datatype instead (called behavior rather than animation, to stress generality):
data Behavior a = Beh (Time -> a)

A drawback of using Animation a as above rather than Time -> a: Cannot use operations on functions, like function composition, directly To compose two behaviours, one must rst pull out the functions, then compose them, and nally build a new box for them:
compose (Beh a1) (Beh a2) = Beh (a1 . a2)

But this is gives unnecessarily costly implementation. For type with only one constructor one can use newtype:
newtype Behavior a = Beh (Time -> a)

(Also possible to dene a special inx operator for behaviour composition) A function to animate behaviours:
animateB :: String -> Behavior Picture -> IO () animateB s (Beh pf) = animate s (picToGraphic . pf)

Gives no overhead in representation! So go for this


SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 8

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

Some useful lifting operations To lift a constant into a behavior:


lift0 :: a -> Behavior a lift0 x = Beh (\t -> x)

Some examples:
emptyB :: Behavior Picture emptyB = lift0 EmptyPic -- ( => Beh (\t -> EmptyPic)) paintB :: Color -> Behavior Region -> Behavior Picture PaintB c = lift1 (\r -> Region c r) -- PaintB c (Beh anim) => Beh (\t -> (\r -> Region c r)(anim t)) -=> Beh (\t -> Region c (anim t)) addB :: (Num a) => Behavior a -> Behavior a -> Behavior a addB = lift2 (+) -- addB (Beh b1) (Beh b2) => Beh (\t -> (+) (b1 t) (b2 t)) -=> Beh (\t -> (b1 t) + (b2 t))

To lift a unary function into a unary function on behaviors:


lift1 :: (a -> b) -> (Behavior a -> Behavior b) lift1 f (Beh a) = Beh (\t -> f (a t))

To lift a binary function into a binary function on behaviors:


lift2 :: (a -> b -> c) -> (Behavior a -> Behavior b -> Behavior c) lift2 g (Beh a) (Beh b) = Beh (\t -> g (a t) (b t))

Etc.
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 10 SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 11

An Illustration of Lifting

Lifting Numerical Operations to Behaviors


Make Behavior a an instance of Num when a is! Then we can indeed write f1 + f2 rather than lift2 (+) f1 f2

f1(t)+f2(t)

How to do it? Heres the class declaration for Num


f1 + f2 (or lift2 (+) f1 f2) f2 f1

f2(t) f1(t)

time

class (Eq a, Show a) => Num a where (+),(-),(*) :: a -> a -> a negate :: a -> a abs, signum :: a -> a fromInteger :: Integer -> a

(Answer on next slide)

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

12

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

13

instance Num a => Num (Behavior a) where (+) = lift2 (+) (*) = lift2 (*) negate = lift1 negate abs = lift1 abs signum = lift1 signum fromInteger = lift0 . fromInteger

There is a subclass constraint on Num: class (Eq a, Show a) => Num a where ... Must make Behavior a an instance of Eq a and Show a rst No natural way to compare and show functions, so dene methods as errors:
instance Eq (Behavior a) where a1 == a2 = error "Cant compare behaviors." instance Show (Behavior a) where showsPrec n a1 = error "<< Behavior >>"

(Hmmm, these lifting functions were not a bad idea) Lifting of some other numerical subclasses given in book, p. 174 For instance, all typical oating-point functions (trigonometric etc.) However, were not quite done yet

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

14

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

15

A Useful Behavior
Time itself can be seen as a behavior:
time :: Behavior Time time = Beh (\t -> t)

New Type Classes for Behaviors

Lets dene a class for empty and over, as suggested earlier:


class Combine a where empty :: a over :: a -> a -> a

A function that always returns the current time at the current time What is time + 5?
time + 5 ==> (lift2 (+)) (Beh (\t -> t)) (Beh (\t -> 5)) ==> Beh (\t -> (\t -> t) t + (\t -> 5) t ) ==> Beh (\t -> t + 5)

Now, this is quite general: intended for situations where over is associative and empty is unit element of over (that is, empty over x x over empty x) Such structures are called monoids in algebra

Aha. A function that always adds ve to current time


SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 16 SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 17

These are our intended instances: Some possible (unexpected) instances:


instance Combine [a] where empty = [] over = (++) instance Combine Integer where empty = 0 over = (+) instance Combine a -> a where -- not valid Haskell 98, empty = \x -> x -- but accepted by some implementations over = (.) instance Combine Picture where empty = EmptyPic over = Over instance Combine a => Combine (Behavior a) where empty = lift0 empty over = lift2 over

A function to put a list of combinable values over each other:


overMany :: Combine a => [a] -> a overMany = foldr over empty

So overMany works both on pictures and picture animations Also, sumInt = overMany :: [Integer] -> Integer, etc.

Etc.
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 18

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

19

More lifting
The red revolving ball can now be written: Some more examples of lifted operations and values:
reg = lift2 Region shape = lift1 Shape ell = lift2 Ellipse red = lift0 Red yellow = lift0 Yellow translate (Beh a1, Beh a2) (Beh r) = Beh (\t -> Translate (a1 t, a2 t) (r t)) revolvingBallB :: Behavior Picture revolvingBallB = let ball = shape (ell 0.2 0.2) in reg red (translate (sin time, cos time) ball)

Supports style of dening functions without mentioning any arguments (Note: sin, cos are lifted oating-point operations, just as the operations in Num)

(Could overload them by a new class, but maybe overkill)

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

20

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

21

Lifting of Predicates and Conditionals


This will prove quite useful. However, We cannot overload lifted relational operations like numerical operations, since relational operations have types of form a -> a -> Bool Thus, the result of comparing two behaviors would have to be a boolean value, not a boolean behavior But we can introduce reasonably understandable names for the lifted operations:
(>*) :: Ord a => Behavior a -> Behavior a -> Behavior Bool (>*) = lift2 (>) cond :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a cond = lift3 (\p c a -> if p then c else a)
SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 22 SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 23

We can now dene a ashing, time-varying color:


flash :: Behavior Color flash = cond (sin time >* 0) red yellow

Will ash between red and yellow depending on the condition

Equivalently, for you who still have a hard time with this lifting stuff:
flash = Beh (\t -> if sin t > 0 then Red else Yellow)

Time Transformations
It can be interesting to change the speed of an animation, or part of it We can do this by time transformations:
timeTrans :: Behavior Time -> Behavior a -> Behavior a timeTrans (Beh f) (Beh a) = Beh (a . f)

A Final Example

Firing a cannon ball with some initial velocity This is a physical simulation problem Movements of rigid bodies is determined by Newtons second law This is a differential equation, acceleration w.r.t. time

Some examples:
timeTrans (2*time) anim -- speeding up an animation with factor 2 timeTrans (5+time) anim over anim -- overlaying an animation with a copy delayed 5 time units timeTrans (negate time) anim -- reversing an animation in time

is second derivative of position

To animate, we need to have the position as function of time Thus, we need to solve the differential equation

More interesting examples in book


SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 24 SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12) 25

Assume 2D-space with normal Earth gravity ( -direction Assume no other forces affect the ball Gives constant force We want position Acceleration

) in the negative

where is mass of ball as function of time


SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

26

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

27

Code
module Cannonball where import Animation import SOEGraphics g :: Float g = 9.81 -- acceleration caused by gravity on earth surface pos :: (Float,Float) -> (Float,Float) -> (Behavior Float, Behavior Float) pos (px,py) (vx,vy) = (Beh (\t -> vx*t + px), Beh (\t -> -g*t^2/2 + vy*t + py)) circ r = ell r r cannonball p0 v0 = reg (lift0 White) (translate (pos p0 v0) (shape (circ 0.2))) fire vel = animateB "Cannon shot" (cannonball (-1,-1) vel) slomo = timeTrans (time/10) slowfire vel = animateB "Slow cannon shot" (slomo (cannonball (-1,-1) vel))

Note separation of aspects: colour, position, and shape

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

28

SoE Chapter 13: A Module of Simple Animations (revised 2004-10-12)

29

Streams: a Common Model

Chapter 14: Programming with Streams


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ October 13, 2004

Streams are innite sequences of data Common in hardware descriptions on architectural level: boxes connected with links, and a stream of data associated with each link

Also in operating systems (process communication, unix pipes) Server-client communication


SoE Chapter 14: Programming with Streams (revised 2004-10-13)
SoE Chapter 14: Programming with Streams (revised 2004-10-13) 1

Streams in Haskell

Streams to Save Memory

Streams can be modeled by innite lists in a lazy language Could dene a data type for innite lists in Haskell: data Stream a = a :^ Stream a However more convenient to use Haskells builtin list data type (and ignore the nite lists)

We can use streams to save work (and memory)! Works for functions whose complexity can be decreased by saving the results of some previous function calls (memoizing ) Seems counterintuitive how can an innite list do that? Sharing of results saves work List elements without references become garbage Thus, a function using a stream can sometimes run in constant space even if the stream is innite

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

Example: the Fibonacci Function


Direct recursion for the Fibonacci Function (mathematical denition):
fib 0 = 1 fib 1 = 1 fib n = fib (n-1) + fib (n-2)

Anyone knows that one can implement fib with a loop, in linear time and constant space Problem with recursive fib is lack of sharing: since one can share fib (n-2) and fib ((n-1)-1), but a compiler cannot reasonably understand that But with streams we can introduce the sharing explicitly

Call tree for fib 6:


fib 6 + fib 5 fib 4 + fib 4 fib 3 fib 3 + + fib 2

Exponential number of calls!


SoE Chapter 14: Programming with Streams (revised 2004-10-13) 4 SoE Chapter 14: Programming with Streams (revised 2004-10-13) 5

A Fibonacci Stream

Let us simulate some steps. Dene add = zipWith (+), or, essentially:
add (x:xs) (y:ys) = (x + y) : add xs ys fibs ==> 1 : 1 : add fibs (tail fibs) ==> 1 : 1 : add (1 : 1 : add fibs (tail fibs)) (1 : add fibs (tail fibs)) ==> 1 : 1 : 2 : add (1 : add fibs (tail fibs)) (add fibs (tail fibs)) ...etc...

Idea:
1 1 2 3 5 8 13 21 34 55, ... = 1 1 1 1 2 3 5 8 13 21 34 55, ... + 1 2 3 5 8 13 21 34 55, ...

Graphically:
fibs = : 1 1 : : add tail 1 1 : add 1 1 2 : : : add Etc.

Haskell code:
fibs :: [Integer] fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
SoE Chapter 14: Programming with Streams (revised 2004-10-13) 6

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

Client-Server Pattern
So exponential blowup of work can be avoided by storing previous Fibonacci values in list But to compute fib n we need a list of length n, right? Well
fib n = fibs !! n (x:xs)!!0 = x (x:xs)!!n = xs!!(n-1)

Servers and clients typically communicate through streams Can model server single client communication with a simple list

-- (skipped some conditions and cases...)


garbage!

(Modelling a server with several clients requires time-stamped streams as in Ch. 15) Mutually recursive stream equation:

fibs!!n 1

: etc

: fibs (tail fibs)!!(n1) 1 1 : etc fibs

client :: [Response] -> [Request] server :: [Request] -> [Response]


server

resps client reqs

Producer-consumer situation, where only constant part of list needs to be kept in memory constant space!
SoE Chapter 14: Programming with Streams (revised 2004-10-13) 8

reqs = client resps resps = server reqs


SoE Chapter 14: Programming with Streams (revised 2004-10-13)

Lazy Pattern Matching


Example: A server that returns value increased by 1 A client that initially sends 1, then echoes what comes back from server
client ys = 1 : ys server xs = map (+1) xs

Let us modify the client to test the rst answer from the server:
client (y:ys) = 1 : if ok y then (y:ys) else error "faulty server" server xs = map (+1) xs reqs = client resps resps = server reqs

You may verify that take 10 reqs

[1,2,3,4,5,6,7,8,9,10] This will lead to nontermination, reqs resps ! Reason: pattern (y:ys) forces evaluation of argument to check whether it matches, before 1 can be output. This leads to innite recursion where nothing ever can be evaluated to match the pattern
10 SoE Chapter 14: Programming with Streams (revised 2004-10-13) 11

This works since xs matches any argument. Thus client ys 1 : ys directly, without having to evaluate ys at all. This gets the recursion going.

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

Example: Modelling a Hardware Structure for Sorting


Two ways to circumvent the problem. 1: skip pattern-matching, using head:
client ys = 1 : if ok (head ys) then ys else error "faulty server"

A simple hardware structure to sort a sequence and store the largest elements:
1 14 3 5 17 min max inf min max inf max inf

2: Lazy pattern-matching :
client ~(y:ys) = 1 : if ok y then y:ys else error "faulty server"

Operates in a synchronous, parallel fashion: every clock tick a new value is shifted in from left and compared with the value stored in the register (This is a systolic array : a simple, efcient, special-purpose system-on-chip structure)
SoE Chapter 14: Programming with Streams (revised 2004-10-13) 13

The tilde defers the pattern-matching until the head or tail is actually needed

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

12

A mathematical model: Cells numbered

Equations:

For input stream of length , a system of recursive equations relating a number of nite streams of length :

,
,

, ,

: stream of input values (indexed ) (

) to cell

Result:

(contents of registers after steps)

: stream of stored values in register of cell

These streams are indexed : each element is numbered

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

14

SoE Chapter 14: Programming with Streams (revised 2004-10-13)

15

Haskell Model
Represent each stream by a list Well use two lists of lists: r for registers, and s for streams between registers A complication: must represent A solution: use type Maybe a rather than a, let Nothing represent Can do this by making Maybe a instance of class Ord whenever a is:
instance Ord a => Ord (Maybe a) where Nothing < Just _ = True Just x < Just y = x < y _ < _ = False

Code:
ssort s0 n = let k = length s0 r = [Nothing : zipWith max (s!!i) (r!!i) | i <- [0..n-1]] s = map Just s0 : [zipWith min (s!!(i-1)) (r!!(i-1)) | i <- [1..n-1]] in map (!! k) r

Note indexing !! of lists, e.g. [1,2,3]!!1 (Indexing starts from 0)

This is already done in Haskell! No need to declare yourself


SoE Chapter 14: Programming with Streams (revised 2004-10-13) 16 SoE Chapter 14: Programming with Streams (revised 2004-10-13) 17

From Animations to Reactive Animations

Chapter 15: A Module of Reactive Animations


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ October 2, 2003 We have seen animations as functions of time But these animations were not interactive Now, lets move to reactive animations, that can change according to input! We then actually get a general high-level model for reactive real-time systems! (Could be anything but animations: control systems, mobile phones, user interfaces, or whatever that can respond to inputs and depend on time) As an example, we will build a little game
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 1

What are Reactive Animations?

Representation of Reactive Animations


We call them behaviors (just like animations)

Animations are functions Time -> a We can model the input (keystrokes, mouse clicks, ) as a stream of time-stamped atomic events: [(UserAction,Time)] Thus, reactive animations can be seen as be functions from the input stream to functions of time: [(UserAction,Time)] -> Time -> a Assume the program executes in an environment with a single, global stream of input atomic events Function reactimate executes reactive animations in this environment (implementation described in Ch. 17, not covered in course)
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 2

The implementation does not use behaviors of type [(UserAction,Time)] -> Time -> a, however Reason: would be very inefcient (see discussion in Ch. 15.2) Instead,
newtype Behavior a = Behavior (([Maybe UserAction],[Time]) -> [a])

We can still think of behaviors as functions from atomic event streams and continuous time (will only use representation-independent primitives) But it is good to understand the conversion (easier to read the book, for instance)
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 3

Understanding the Representation of Behaviors


Animations are not continuous in reality, but created from samples of the animated entity at certain times The actual representation ([Maybe UserAction],[Time]) -> [a] depends on a conversion from continuous time to sampled time:
b a > b [a] > [b]

Behaviors are however also functions from streams of atomic events The representation comes from merging this input stream with the stream of times at which we sample the animation This means we must create a pair (event,time) for each sample time, where event is an empty event (absence of real event) Can use Maybe type and represent empty events by Nothing See gure on next slide

So a function a -> b yields a sampled function [a] -> [b] (list of inputs to list of outputs)
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 4 SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 5

Events
Resulting stream of values Just x1 Just x2 Nothing Nothing Just x3 Nothing Event stream time t1
event

The reactive model also contains event streams These are streams of atomic events that occur depending on input events and time Do not mix them up with the atomic events! We can think of them as functions from input events and time to time-stamped atomic events
type Event a = [(UserAction,Time)] -> Time -> [(a,Time)]

t2
event

t3
sample

t4
sample

t5
event

t6
sample

A representation [(Maybe UserAction,Time)] -> [a], can be unzipped to ([Maybe UserAction],[Time]) -> [a] View: global input stream of time-stamped events, some are real external events, some are events sampling the animation function
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 6

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

Some Basic Behaviors


As for behaviors we convert to sampled time. The event stream is supposed to instantly produce an output event for every input event (Just x,t) (external event) produces output of the form (Just y,t) (Nothing,t) (sample event) produces output (Nothing,t) So event streams are represented as
newtype Event a = ([Maybe UserAction],[Time]) -> [Maybe a]

A number of primitives are the same as for the simpler animations in Ch. 13: Time:
time :: Behavior Time

Behavior that yields current time, regardless of user input

which is really the same as Behavior (Maybe a), only the name differs

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

Standard Lifting Functions

Some Standard Liftings


paint = lift2 Region -- takes colour and region as args

Lifting functions as for animations:


lift0 :: a -> Behavior a lift1 :: (a -> b) -> (Behavior a -> Behavior b) lift2 :: (a -> b -> c) -> (Behavior a -> Behavior b -> Behavior c)

red

= lift0 Red -- similar for the other colours

shape = lift1 Shape ell x y = shape (lift2 Ellipse x y) rec x y = shape (lift2 Rectangle x y) translate :: (Behavior Float,Behavior Float) -> Behavior Region -> Behavior Region translate = ...see book, it does do what youd expect... over = lift2 Over (<*) = lift2 (<) -- (also lifting >, &&, || to >*, &&*, ||*)
11

Used to make Behavior a member of numerical classes whenever a is, just as for animation Also used for some standard liftings, see next page

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

10

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

A Simple Example

Reactive Behaviors

A ball that circles the origin with distance 1, being painted with some (possibly time- and user-input-varying) color behavior color1:
ball1 :: Behavior Picture ball1 = paint color1 circ circ :: Behavior Region circ = translate (cos time, sin time) (ell 0.2 0.2)

Behaviors that behave initially in some way, and then change to some other behavior when a certain event occurs The new behavior is carried in the event : typical functional programming style!
untilB, switch :: Behavior a -> Event (Behavior a) -> Behavior a

Just as in Ch. 13 but with new data types (this animation is not interactive, unless color1 is) Note that numerical constants 0.2 are lifted to constant behaviors
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 12

f untilB e: Behave as f until time of rst event in e, then change to behavior carried by that event switch is a variation of untilB that loops, and on each new event switches to the event-carried behavior
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 13

Predened Events
Different event streams can be dened by ltering out certain kinds of events from the global event stream For instance, interesting to lter out different button presses, and keystrokes Such predened event streams in the library:
lbp :: Event ()

How to Create Events Carrying Behaviors


Two (inx) operators:
(->>) :: Event a -> b -> Event b

evs ->> x: replace contents of every event in evs with x Example: lbp ->> 17 yields event containing 17 for each left button press
(=>>) :: Event a -> (a -> b) -> Event b

Returns an event containing () every time the left mouse button is pressed
key :: Event Char

evs =>> f: transform contents of every event in evs with f Example: key =>> (\c -> toUpper c) yields an event containing the upper-case character for each keystroke Note that evs ->> x evs =>> (\_ -> x)
15

Returns an event containing a character every time the corresponding key is pressed
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 14

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

Some Simple Examples


A color behavior that starts out as white, changes to red/blue/yellow when key R/B/Y is pressed, and changes back to white when any other key is pressed:
color6 = white switch (key =>> \c -> case c of R -> red B -> blue Y -> yellow _ -> white)

A color behavior that starts out as red, and changes to blue when the left button is pressed:
color1 :: Behavior Color color1 = red untilB (lbp ->> blue)

A recursive color behavior that changes between red and blue when the left button is pressed:
color1r = red untilB lbp ->> blue untilB lbp ->> color1r

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

16

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

17

Predicate Events

Integration
integral :: Behavior Float -> Behavior Float

when :: Behavior Bool -> Event () when b: a ()-event is inserted every time b changes from False to True So it triggers an event every time a condition changes to true Example: when (time >* 2 &&* time <* 5) ||* (time >* 10) Can be used for instance in animations to detect collisions between moving objects, or to dene time-triggered behaviors

Integrates a oating-point behavior over time (Implemented by approximating the integral with a sum, formed from the values of the behavior at sampled times) Extremely useful for realistic animations, where a body is moving under the inuence of forces (remember Newtons second law!)

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

18

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

19

Example

Parallel Composition
Merge of two event streams:

The -coordinate of a moving body as a function of time, from some acceleration given by Newtons second law. Integrating the acceleration once gives velocity, and twice yields position
startpos = 0 :: Behavior Float startvel = 10 :: Behavior Float xacc = ...complex definition... :: Behavior Float -- acceleration xvel = integral xacc + startvel -- velocity xpos = integral xvel + startpos -- position

(.|.) :: Event a -> Event a -> Event a

Will yield the union of the two event streams with the events in the right time order Events of left stream go rst if appearing at same time in both streams Example:
color2 = red untilB (lbp ->> blue .|. key ->> yellow)

(Same can be done for the -coordinate, to give full movement)

A color behavior that starts as red and switches to blue on left button press, or yellow on any key, whichever comes rst Thus, b1 .|. b2 is similar to running b1 and b2 as parallel threads
20 SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 21

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

Snapshot
To sample a behavior when an event occurs:
snapshot :: Event a -> Behavior b -> Event (a,b)

Two Variations on Switch

Useful to have behaviors that update themselves when some event happen
step :: a -> Event a -> Behavior a a step e = lift0 a switch (e =>> lift0)

The pair contains the value of the event and the current value of the behavior So in a sense it samples the behavior for each input event A variation that throws away the rst component:
snapshot_ :: Event a -> Behavior b -> Event b snapshot_ e b = (e snapshot b) =>> snd

A behavior that starts off as a and then switches to the successive values of the events of e Think of a sample and hold-circuit A step key, starts as A and then switches to last pressed key

Example: key snapshot_ time, a stream of events that contains the current time for each keystroke
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 22 SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 23

stepAccum successively applies functions carried by an event stream


stepAccum :: a -> Event (a->a) -> Behavior a

stepAccum can be dened in terms of our previously dened behavior primitives:


a stepAccum e = b where b = a step ((e snapshot b) =>> uncurry ($)) uncurry :: (a -> b -> c) -> (a,b) -> c uncurry f (x,y) = f x y -- the opposite of currying f $ x = f x -- explicit operator for function application

Example: counter = 0 stepAccum lbp ->> (+1) A counter that increases every time the left mouse button is pressed Think of a stepAccum funcevs as a program variable, with an initial value of a, that for each event f in funcevs is updated by applying f to the currenct contents Interesting application in interactive games: use it to generate a random number event stream, where the seed for the generator is updated at each event
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 24

(Thus, uncurry ($) (f,x)

f $ x

f x)

It takes some time to digest this. But note the recursive use of b! The snapshot will sample the current value of b, which is then used to compute its new value
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 25

Mouse Motion
We model mouse motion as a pair of behaviors, which give the x- and y-coordinates as functions of time:
mouse :: (Behavior Float, Behavior Float)

Paddleball
Now we have nally reached the level of pong :-) Paddleball - a game with three walls, a bouncing ball, and a mouse-controlled paddle to prevent the ball going off the screen at the fourth side
paddleball vel = walls over paddle over pball vel walls = let upper = paint blue (translate ( 0,1.7) (rec 4.4 0.05)) left = paint blue (translate (-2.2,0) (rec 0.05 3.4)) right = paint blue (translate ( 2.2,0) (rec 0.05 3.4)) in upper over left over right paddle = paint red (translate (fst mouse, -1.7) (rec 0.5 0.05))
26 SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02) 27

To have a ball, whose color changes with keyboard inputs, follow the mouse:
ball = paint color4 circ3 circ3 = translate mouse (ell 0.2 0.2) color4 = white switch ((key snapshot color4) =>> \(c,old) -> case c of R -> red B -> blue Y -> yellow _ -> lift0 old)
SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

ppball vel = let xvel xpos xbounce yvel ypos ybounce

vel stepAccum xbounce ->> negate integral xvel when (xpos >* 2 ||* xpos <* -2) vel stepAccum ybounce ->> negate integral yvel when (ypos >* 1.5 ||* ypos between (-2.0,-1.5) &&* fst mouse between (xpos-0.25,xpos+0.25)) in paint yellow (translate (xpos, ypos) (ell 0.2 0.2))

= = = = = =

x between (a,b) = x >* a &&* x <* b

SoE Chapter 15: A Module of Reactive Animations (revised 2003-10-02)

28

Files Etc.

Chapter 16: Communicating With the Outside World


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007

Haskell has a fairly conventional set of le operations These are IO actions Lets have a closer look at them!

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

File Handling

Reading and Writing Files

Opening and closing les:


openFile :: FilePath -> IOMode -> IO Handle hClose :: Handle -> IO () Type FilePath = String Data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode

Some le operations in write mode:


hPutChar :: Handle -> Char -> IO () hPutStr :: Handle -> String -> IO () hPutStrLn :: Handle -> String -> IO () hPrint :: Show a => Handle -> a -> IO () ----write write write write a a a a character string line Showable value

Some le operations in read mode:


hGetChar :: Handle -> IO Char -- read a character hGetLine :: Handle -> IO String -- read a line hGetContents :: Handle -> IO String -- read full contents of file, -- lazily
SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17) 2 SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17) 3

File Handling Without Handles

Channels

Write to a le without handles:


writeFile :: FilePath -> String -> IO () appendFile :: FilePath -> String -> IO ()

Haskell also recognizes channels such as stdin, stdout, and stderr (straightforward for those who know unix) These can be used as handles Some examples:
getChar = hGetChar stdin putChar = hPutChar stdout

But using these commands means opening and closing the le each time. With explicit le handling we can avoid this inefciency

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

More Advanced File I/O Operations

Exception Handling

Haskell has a standard library (module) for more advanced le handling and I/O in general Importing this library gives access to the functions for this: import System.IO

Haskell has exception handling for IO actions Errors (exceptions) can be generated for instance from attempting to open a non-existing le, or reading the end-of-le We may want to recover from these errors Exception handing can be used for this Exceptions have type IOError

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

Catching Exceptions

Example: variation of getChar returning newline if any exception is thrown:


getChar :: IO Char getChar = catch getChar (\e -> return \n)

A function to catch exceptions:


catch :: IO a -> (IOError -> IO a) -> IO a

A renement: return newline if EOF is encountered, otherwise pass exception upwards (nested exception handling is possible):
getChar :: IO Char getChar = catch getChar (\e -> if isEOFError e then return \n else ioError e)

First argument is action to be executed. If an exception is thrown, then it is handled by the second argument which reads the exception and returns an IO action to be executed If no exception handling is provided, Haskell invokes a default handler that prints an error message and terminates the program

isEOFError :: IOError -> Bool tests for EOF exception ioError throws the exception upwards More examples in book!

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

SoE Chapter 16: Communicating With the Outside World (revised 2007-08-17)

The Topics

Lambda Calculus and Type Inference


Bjrn Lisper Dept. of Computer Science and Engineering Mlardalen University [email protected] http://www.idt.mdh.se/blr/ August 17, 2007 Lambda Calculus: a formal calculus for functions and how to compute with them Type Inference: how to nd the possible type(s) of expressions, without explicit typing

Lambda Calculus and Type Inference (revised 2007-08-17)

Lambda Calculus and Type Inference (revised 2007-08-17)

Lambda Calculus

The Simple Untyped Lambda Calculus


A term in this calculus is:

Formal calculus Invented by logicians around 1930 Formal syntax for functions, and function application Gives a certain computational meaning to function application Theorems about reduction order (which possible subcomputation to execute rst) This is related to call-by-value/call-by-need Several variations of the calculus
Lambda Calculus and Type Inference (revised 2007-08-17) 2

a variable x, a lambda-abstraction x.e, or an application e1 e2 Some examples: x xy xx x.(x y ) (x.x) y x.y.x.x

Any term can be applied to any term, no concept of (function) types Syntax: function application binds strongest, x.x y = x.(x y ) = (x.x) y
Lambda Calculus and Type Inference (revised 2007-08-17) 3

Untyped Lambda Calculus with Constants

Equivalences
Some lambda-expressions are considered equivalent (e1 e2)

We can extend the syntax with constants, for instance: 1, 17, +, [ ], : We can then write terms closer to Haskell, like 17 + x x.(x + y ) l.x.(l : x)

Rule 1: change of name of bound variable gives an equivalent expression (alpha-conversion) So x.(x x) y.(y y ) Quite natural, right? However, beware of variable capture: x.y.x y.y.y Renaming must avoid name clashes with locally bound variables Note that (x.y.x) 17 = y.17, whereas (y.y.y ) 17 = y.y . Different!
4 Lambda Calculus and Type Inference (revised 2007-08-17) 5

Every Haskell program can be translated into an intermediate form, which essentially is a lambda calculus with constants Some constants (like +) can be given a computational meaning, more on this later
Lambda Calculus and Type Inference (revised 2007-08-17)

Beta-reduction
A lambda abstraction applied to an expression can be beta-reduced : (x.x + x) 9 9 + 9 Beta-reduction means substitute actual argument for symbolic parameter in function body Works also with symbolic arguments: (x.x + x) (x.y z ) (x.y z ) + (x.y z ) However, beware of variable capture: (x.y.(x + y )) y y.(y + y ) The x is to rst rename the bound variable y : (x.y.(x + y )) y (x.z.(x + z )) y z.(y + z )
Lambda Calculus and Type Inference (revised 2007-08-17) 6

Extending the Equivalence

We consider expressions equal if there is a way to convert them into each other, through beta-reductions or inverse beta-reductions For instance, (x.x) 17 (y.17) z since (x.x) 17 17 (y.17) z

Lambda Calculus and Type Inference (revised 2007-08-17)

Some Encodings
An example of how C ON D works: Many mathematical concepts can be encoded in the lambda-calculus That is, they can be translated into the calculus For instance, we can encode the boolean constants, and a conditional (functional if-then-else): C ON D T RU E A B T RU E F ALSE = x.y.x = x.y.y (p.q.r.(p q r )) (x.y.x) A B (q.r.((x.y.x) q r )) A B (r.((x.y.x) A r )) B (x.y.x) A B y.A B A

C ON D = p.q.r.(p q r )

Try evaluating C ON D F ALSE A B yourself!


8 Lambda Calculus and Type Inference (revised 2007-08-17) 9

Lambda Calculus and Type Inference (revised 2007-08-17)

Nontermination
Boolean connectives (and, or) can also be encoded As well as lists, integers, . . . Actually anything you can do in a functional language! Consider this expression: (x.x x) (x.x x) What if we beta-reduce it? (x.x x) (x.x x) (x.x x) (x.x x) Whoa, we got back the same! Scary . . . Clearly, we can reduce ad innitum The lambda-calculus thus contains nonterminating reductions
Lambda Calculus and Type Inference (revised 2007-08-17) 10 Lambda Calculus and Type Inference (revised 2007-08-17) 11

Recursion
Now consider this expression: h.(x.h (x x)) (x.h (x x)) Lets call it Y What if we apply it to a function f ? Y f = = h.(x.h (x x)) (x.h (x x)) f (x.f (x x)) (x.f (x x)) f ((x.f (x x)) (x.f (x x))) f (Y f )

Y is called xed-point combinator It encodes recursion To see why, consider the recursive denition x=f x The solution is x = f f f Likewise, Y f = f (Y f ) = f f (Y f ) = f f f Thus, x = Y f ! Note that all recursive denitions can be written on the form x = f x
12 Lambda Calculus and Type Inference (revised 2007-08-17) 13

Hmm, we got back f applied to Y f


Lambda Calculus and Type Inference (revised 2007-08-17)

Reduction Strategies

Does the order of reducing redexes matter? Well, yes and no:

Any application of a lambda-abstraction in an expression can be beta-reduced Each such position is called a redex An expression can contain several redexes Can you nd all redexes in this expression? (x.((y.y ) x) ((y.y ) x) Try reduce them in different orders!

Theorem: if two different reduction orders of the same expression end in expressions that cannot be further reduced, then these expressions must be the same However, we can have potentially innite reductions: (x.y ) ((x.x x) (x.x x)) Reducing the outermost redex yields y But the innermost redex can be reduced innitely many times nontermination! So the order does matter, as regards termination anyway!

Lambda Calculus and Type Inference (revised 2007-08-17)

14

Lambda Calculus and Type Inference (revised 2007-08-17)

15

Normal Order Reduction


Some other reduction orders do not terminate Consider this slight adaptation of the previous example: (x.x.y ) (x.x) ((x.x x) (x.x x)) Let us draw it as a tree:
@

This is not a coincidence! To reduce the leftmost-outermost redex in each step is called normal order reduction Theorem: if there is a reduction order that terminates, then normal order reduction terminates

@ \x > \x > y \x > x \x > x x

@ \x > x x

Normal order reduction corresponds to call-by-need in functional languages

Reducing the leftmost-outermost redex twice yields y


Lambda Calculus and Type Inference (revised 2007-08-17) 16 Lambda Calculus and Type Inference (revised 2007-08-17) 17

Type Inference
There is an interesting theory behind Haskell-style type inference You have seen that Haskell systems can nd types for expressions:
y f = f (y f) y :: (a -> a) -> a

To infer means to prove, or to deduce A type system is a logic, whose statements are of form expression e has type To infer a type means to prove a statement like above A type inference algorithm nds a type if it exists: it is thus a proof search algorithm Such an algorithm exists for Haskells type system

As we have mentioned, the most general type is always found

Lambda Calculus and Type Inference (revised 2007-08-17)

18

Lambda Calculus and Type Inference (revised 2007-08-17)

19

Hindley-Milners Type System


A language of types: Haskells type system extends a simpler type system known as Hindley-Milners type system (HM) HM does not have type classes, and it is dened over a simple lambda-calculus language Here, we will briey describe a subset of HM: Language is lambda-calculus with constants (also known functions, like +) Constants have typing given in advance Recursion can be encoded through constant Y (xed-point combinator) type constants (like I nt) type variables function types ( is a type constructor ) type schemes . Other type constructors (for list types etc) can easily be added Type schemes like . correspond to polymorphic Haskell types like a -> a
20 Lambda Calculus and Type Inference (revised 2007-08-17) 21

Lambda Calculus and Type Inference (revised 2007-08-17)

Statements

Inference Rules
Axioms and allowed proof steps are given as a set of inference rules

Statements of form A

e : , where e is expression and is a type

Each inference rule has a number of premises and a conclusion Often written on the form premise 1 premise n conclusion Example (modus ponens in propositional logic): P P = Q Q

A is a set of assumptions, of form x : (read: variable x has type ) A e : is read under the assumptions on typings of variables in A, the expression e can have type So in order to prove such a statement, we must guess some typings of variables in e and then check that we can give e a consistent type with these assumptions The key in type inference is to make these guesses systematically

Axioms are inference rules without premises


22 Lambda Calculus and Type Inference (revised 2007-08-17) 23

Lambda Calculus and Type Inference (revised 2007-08-17)

Hindley-Milner Inference Rules


A selection of rules from the HM inference system: A {x : } x: [V AR] [ABS ] [ AP P ] [S P EC ]

An Example

Best way to understand inference rules is to see a derivation Lets infer a type for (y.(t ail y )) n il Extend language of types with list types [ ] Assume given typings for constants: A = {n il : .[], t ail : .[] []}

A {x : } e : A x.e : A e: A A ee : A e : . A e : [/] e :

( [/] stands for with replacing every occurrence of )


Lambda Calculus and Type Inference (revised 2007-08-17) 24 Lambda Calculus and Type Inference (revised 2007-08-17) 25

Derivation

Inference Algorithm
There is a classical algorithm for type inference in the HM system

A n il : .[] T y.(t ail y ) : [ ] [ ] A n il : [ ] A (y.(t ail y )) n il : [ ]

Called algorithm W Basically a systematic and efcient way to infer types like we did in the example The algorithm uses unication, remember this when you learn logic programming!

where A {y : [ ]} t ail : .[] [] A {y : [ ]} A {y : [ ]} t ail : [ ] [ ] A {y : [ ]} t ail y : [ ] y : [ ]

It has been proved that algorithm W always yields a most general type for any typable expression Most general means that any other possible type for the expression can be obtained from the most general type by instantiating its type variables
26 Lambda Calculus and Type Inference (revised 2007-08-17) 27

T =

Lambda Calculus and Type Inference (revised 2007-08-17)

A More Practical Type Inference Example


Type inference can be seen as equation solving: every declaration gives rise to a type equation constraining the types for the untyped identiers These equations can be solved to nd the types
length [] = 0 length (x:xs) = 1 + length xs

Dene

In our example, we already know:


0 :: Int 1 :: Int (+) :: Int -> Int -> Int [] :: [a] (:) :: b -> [b] -> [b]

Derive the most general type for length! For simplicity, assume that 0 :: Int, 1 :: Int, and (+) :: Int -> Int -> Int See next four slides for how to do it . . .

Note different type variable names in types of [] and (:), to make sure theyre not mixed up
28 Lambda Calculus and Type Inference (revised 2007-08-17) 29

Lambda Calculus and Type Inference (revised 2007-08-17)

Second declaration Solving the equation for the rst declaration:


length [] = 0 length (x:xs) = 1 + length xs

Must rst nd possible types for x, xs, x:xs Assume x :: e, xs :: f e = b, f = [b] (or else x:xs is not well-typed), then x:xs :: [b] Left-hand side: OK if [b] = [a] (so xs :: [a] and x:xs :: [a]), and then length (x:xs) :: Int Right-hand side: xs :: [b], length :: [a] -> Int and xs :: [a] gives length xs :: Int 1 :: Int, length xs :: Int, (+) :: Int -> Int -> Int gives 1 + length xs :: Int
30 Lambda Calculus and Type Inference (revised 2007-08-17) 31

length :: c -> d (since it is applied to one argument) c = [a] (from what we know about the type of []) d = Int (since length [] :: d, 0 :: Int, and both sides of the declaration must have the same type) Thus, length :: [a] -> Int Is this consistent with the second case in declaration of length?

Lambda Calculus and Type Inference (revised 2007-08-17)

Applications of Type Inference


Thus type of LHS = type of RHS! Were done. Result: length :: [a] -> Int Must be a most general type since we were careful not to make any stronger assumptions than necessary about any types (In the formal type system, we would obtain length : .[] Int ) HM-style type systems used in some advanced functional languages, most notably ML and Haskell Similar type inference systems can be used for program analysis Types (not the usual ones) can stand for properties e : then means expression (program) e has property Can be used in optimizing compilers Another application: dimensional analysis, to nd whether equations are sound w.r.t. physical dimensions
Lambda Calculus and Type Inference (revised 2007-08-17) 32 Lambda Calculus and Type Inference (revised 2007-08-17) 33

You might also like