cse536 functional programming 1 6/10/2015 lecture #6, oct 13, 2004 reading assignments –read...

31
Cse536 Functional Programming 1 03/27/22 Lecture #6, Oct 13, 2004 Reading Assignments Read chapter 5 of the Text Polymorphic and Higher-Order Functions Read chapter 6 of the Text Shapes III: Perimeters of Shapes Assignment #3 – Now in Assignments directory » Assigned: Oct. 13, 2004 » Due, in class: Wednesday, Oct. 20, 2004 Today’s Topics Polymorphic Functions Polymorphic datatypes » Type Constructors define polymorphic Constructor functions Recursive datatypes Higher Order functions Perimeters of Shapes

Post on 19-Dec-2015

216 views

Category:

Documents


2 download

TRANSCRIPT

Cse536 Functional Programming

104/18/23

Lecture #6, Oct 13, 2004• Reading Assignments

–Read chapter 5 of the TextPolymorphic and Higher-Order Functions

–Read chapter 6 of the TextShapes III: Perimeters of Shapes

–Assignment #3 – Now in Assignments directory» Assigned: Oct. 13, 2004 » Due, in class: Wednesday, Oct. 20, 2004

•Today’s Topics –Polymorphic Functions– Polymorphic datatypes

» Type Constructors define polymorphic Constructor functions

–Recursive datatypes– Higher Order functions–Perimeters of Shapes

Cse536 Functional Programming

204/18/23

Polymorphic Length

len :: [a] -> Int

len [] = 0

len (x:xs) = 1 + len xs

• Polymorphic functions don’t “look at” their polymorphic arguments.

• They use the same code now matter what the type of their polymorphic arguments.

“a” is a type variable. It islowercase to distinguish it

from types, which are uppercase.

Cse536 Functional Programming

304/18/23

Polymorphism

• Consider: tag1 x = (1,x)? :type tag1

tag1 :: a -> (Int,a)

• Other functions have types like this consider (++)? :type (++)

(++) :: [a] -> [a] -> [a]

? :type ([1,2]++)

([1,2] ++) :: [Int] -> [Int]

• What are some other polymorphic functions and their types?– id :: – reverse :: – head :: – tail :: – (:) ::

Cse536 Functional Programming

404/18/23

Polymorphic data structures• Polymorphism originates from data structures

that don’t care what kind of data they store.

id :: a -> a -- The ultimate

-- polymorphic function

reverse :: [a] -> [a] -- lists

tail :: [a] -> [a]

head :: [a] -> a

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

tag1 :: Num a => b -> (a,b) -- tuples

• How do we define new data structures with “holes” that can be polymorphic?

Cse536 Functional Programming

504/18/23

Parametric Type Constructors• Polymorphic types

data Option a = NONE | SOME a– Note NONE is a constant, SOME is a function

• We can have: type example with that type

Option Int SOME 3Option String SOME "x"Option (Int,Bool) SOME (3,True)

even Option (Option Int) • Give some examples with the type Option (Option Int)

The type parameter to Optioncauses it’s constructors to

be polymorphic

Cse536 Functional Programming

604/18/23

Why use Option?pos :: Eq a => a -> [a] -> Option Int

pos a l =

let find a [] n = NONE

find a (x:xs) n =

if a==x

then SOME n

else find a xs (n+1)

in find a l 0

? pos 4 [1,2,3,4,5]

SOME 3

? pos 4 [1,5,6,7]

NONE

• Option is a type constructor since it constructs new types from old ones.

Cse536 Functional Programming

704/18/23

Types Constructors with multiple inputs

data Pair a b = Pair (a,b)

data Pair2 a b = Pair2 a b

• In Haskell sometimes the Type constructor and the value constructor have the same name.? :t Pair(2,"x")

Pair (2,"x") :: Pair Int [Char]

? :t Pair ((),Pair (2,3))

Pair ((),Pair (2,3)) :: Pair () (Pair Int Int)

• Domain of constructors - To use tuples or not? That is the question!? :t Pair

Pair :: (a,b) -> Pair a b

? :t Pair2

Pair2 :: a -> b -> Pair2 a b

Cse536 Functional Programming

804/18/23

Recursive types• Well known and loved lists

data [a] = [] | a : [a]

• You can define your own !data Mylist a = Nil

| Cons (a,Mylist a)

• But be warned! The two are not the same type.? :t Cons

Cons :: (a,Mylist a) -> Mylist a

? Cons(3,2:[])

ERROR: Cannot derive instance in expression

*** Expression : Cons (3,[ 2 ])

*** Required instance: Monad Mylist

Lists are predefined, butcould be defined this way

Cse536 Functional Programming

904/18/23

Recursive type constructors with multiple inputs

data Twolist a b = Twonil

| Acons (a,Twolist a b)

| Bcons (b,Twolist a b)

append2 Twonil ys = ys

append2 (Acons(a,xs)) ys = Acons(a,append2 xs ys)

append2 (Bcons(b,xs)) ys = Bcons(b,append2 xs ys)

rev2 Twonil = Twonil

rev2 (Acons(a,t)) = append2 (rev2 t) (Acons(a,Twonil))

rev2 (Bcons(b,t)) = append2 (rev2 t) (Bcons(b,Twonil))

? :t rev2

rev2 :: Twolist a b -> Twolist a b

? append2 (Acons(2,Twonil))(Bcons(4,Twonil))

Acons (2,Bcons (4,Twonil))

Cse536 Functional Programming

1004/18/23

Recursive type constructors with 0 inputs

data Nat = Zero | Succ Nat;

• Is there any polymorphism here? Why not?• Write the addition function for Nat?

add :: Nat -> Nat -> Nat

add =

• Write a fun from positive Int to Nat. toNat :: Int -> Nat? toNat 3

Succ (Succ (Succ Zero))

toNat =

Cse536 Functional Programming

1104/18/23

Polymorphism from functions as arguments

• Another source of polymorphism comes from functions which take functions as arguments.

applyTwice f x = f(f x)

Main> :t applyTwice

applyTwice :: (a -> a) -> a -> a

• What’s the type of z below?

z f x y = (f x, f y)

Cse536 Functional Programming

1204/18/23

Polymorphism: Functions returned as values

• Consider:

k x = (\ y -> x)

? (k 3) 5

3– What’s the type of K?

• Another Example:

compose f g = \ x -> f (g x)

– What’s the type of compose ?

Cse536 Functional Programming

1304/18/23

Higher order functions abstract control

• Higher order functions capture control patterns

transList :: [Vertex] -> [Point]

transList [] = []

transList (p:ps) = trans p : transList ps

putCharList :: String -> [IO ()]

putCharList [] = []

putCharList (c:cs) = putChar c : putChaList cs

map f [] = []

map f (x:xs) = (f x):(map f xs)

Cse536 Functional Programming

1404/18/23

When do you define a higher order function?

• Recognizing patterns is the keymysum [] = 0

mysum (x:xs) = (+) x (mysum xs)

myprod [] = 1

myprod (x:xs) = (*) x (myprod xs)

myand [] = True

myand (x:xs) = (&&) x (myand xs)

• Note the similarities in definition and in use? mysum [1,2,3]

6

? myprod [2,3,4]

24

? myand [True, False]

False

Cse536 Functional Programming

1504/18/23

Abstracting myfoldr op e [] = e

myfoldr op e (x:xs) =

op x (myfoldr op e xs)

? :t myfoldr

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

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

6

?

Cse536 Functional Programming

1604/18/23

Using foldr• Once we’ve captured a pattern we should

use it!mysum = foldr (+) 0

myprod = foldr (*) 1

myand = foldr (&&) True

• Study the definitions below. Define equivalent functions in terms of foldr.map f [] = []

map f (x:xs) = (f x):(map f xs)

map f = foldr . . .

append [] ys = ys

append (x:xs) ys = x : (append xs ys)

append xs ys = foldr . . .

Cse536 Functional Programming

1704/18/23

foldl• Let:

x = [1,2,3,4]

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

foldr (+) e x =

1 + (2 + (3 + e))

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

foldl (+) e x =

(((e + 1) + 2) + 3) + 4

– Can you define foldl?

Cse536 Functional Programming

1804/18/23

Why foldl and foldr?• Grouping from the left or the right matters

in some computations.

• Consider the two defintions

concat1 :: [[a]] -> [a]

concat1 = foldr (++) []

concat2 :: [[a]] -> [a]concat2 = foldl (++) []

• Which is more efficient?

concat1 [x,y,z] = x ++ (y ++ z)

concat2 [x,y,z] = (x ++ y) ++ z

Cse536 Functional Programming

1904/18/23

Reverserev [] = []

rev (x:xs) = (rev xs) ++ [x]

• What’s the cost (in number of (:)’s) for rev [1,2,3,4]?

• Can we do better?– Use an accumulating parameter

rev2 [] ys = ys

rev2 (x:xs) ys = . . .

rev x = rev2 x []

• Can we write rev2 as a fold?– Which one do we use foldr or foldl?

Cse536 Functional Programming

2004/18/23

Artihmetic Sequences• Special syntax for computing lists with

regular properties.

[1 .. 6] = [1,2,3,4,5,6]

[1,3 .. 9] = [1,3,5,7,9]

• Infinite lists too!

take 9 [1,3..] = [1,3,5,7,9,11,13,15,17]

take 5 [5..] = [5,6,7,8,9]

Cse536 Functional Programming

2104/18/23

The perimeter of a Shape• To compute the perimeter we need a function

with four equations (1 for each constructor of Shape)

• The first three are easy …

perimeter :: Shape -> Float

perimeter (Rectangle s1 s2) = 2*(s1+s2)

perimeter (RtTriangle s1 s2) = s1 + s2 + sqrt(s1^2+s2^2)

perimeter (Polygon pts) = foldl (+) 0 (sides pts)

• Provided we can compute a list of the length of the sides of a polygon. This shouldn’t be too difficult since we can compute the distance between two points with distBetween

s1

s2

s1

s2

Cse536 Functional Programming

2204/18/23

Sides is easy recursively

sides :: [Vertex] -> [Side]

sides [] = []

sides (p:pts) = aux (p:pts)

where aux (p1:p2:pts) = (distBetween p1 p2) :

(aux (p2:pts))

aux (pn:[]) = distBetween pn p : []

-- aux [pn] = [distBetween pn p]

• But can we do it as a seasoned functional programmer might do it?

Cse536 Functional Programming

2304/18/23

Visualize what’s happening• The list of vertex, vs = [A,B,C,D,E]

• distance between (A,B) (B,C) (C,D) (D,E) (E,A)

• Can we compute these pairs as a list?

[(A,B),(B,C),(C,D),(D,E),(E,A)]

• Yes by zipping the following two lists:

[A,B,C,D,E] [B,C,D,E,A]

zip vs ((tail vs)++[head vs])

A

B

C

DE

Cse536 Functional Programming

2404/18/23

Second version of sides

sides2 :: [Vertex] -> [Side]

sides2 pts = zipWith distBetween pts

(tail pts ++ [head pts])

In class exercise, define: zipWith

zipWith f ...

Cse536 Functional Programming

2504/18/23

• The perimeter of an ellipse is given by the summation of an infinite series. For an ellipse with radii r1 and r2

p = 2r1(1 - si)

where s1 = 1/4 e2

si+1 = si (2i-1)(2i-3) e2 for i>= 1

4i2

e = sqrt(r1* r

1 - r

2 * r

2)/r1

Given si its is easy to compute the next value in the series s

i+1

Perimeter of an Ellipse

Cse536 Functional Programming

2604/18/23

Computing the series

nextEl:: Float -> Float -> Float -> Float

nextEl e s i =

s*(2*i-1)*(2*i-3)*(e^2) / (4*i^2)

• We want to compute [s1,s2,s3, …]• for fixed eaux s i = nextEl e s i

[s1,

aux s1 1,

aux (aux s1 1) 2,

aux (aux (aux s1 1) 2) 3, …]

si+1 = si (2i-1)(2i-3) e2 4i2

Can we capturethis pattern?

Cse536 Functional Programming

2704/18/23

Scanl (scan from the left)[s1,

s2 = f s1 1,

s3 = f s2 2 = f(f s1 1) 2,

s4 = f s3 3 = f(f (f s1 1) 2) 3,

…]

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

scanl f seed [] = seed : []

scanl f seed (x:xs) = seed : scanl f newseed xs

where newseed = f x seed

scanl aux s1 [1,2 ..]

Cse536 Functional Programming

2804/18/23

We get the following pattern

s1 = 1/4 e2

s1 = 0.25 * ((r1^2 - r2^2) / r1)

where r1 and r2 are the radii of the ellipse

[s1,

s2 = aux s1 1,

s3 = aux s2 2,

s4 = aux s3 3,

…]

Cse536 Functional Programming

2904/18/23

r2 = 1.5

r1 = 2.1

e =

sqrt (r1^2 - r2^2) / r1= 0.699854

[s1 = 0.122449, s2 = 0.0112453, s3 = 0.00229496, s4 = 0.000614721, s5 = 0.000189685,…]

Note how quicklythe series gets realsmall ...

Cse536 Functional Programming

3004/18/23

Putting it all together

perimeter (Ellipse r1 r2)

| r1 > r2 = ellipsePerim r1 r2

| otherwise = ellipsePerim r2 r1

where ellipsePerim r1 r2

= let e = sqrt (r1^2 - r2^2) / r1

s = scanl aux (0.25*e^2)

(map intToFloat [2..])

aux s i = nextEl e s i

test x = x > epsilon

sSum = foldl (+) 0 (takeWhile test s)

in 2*r1*pi*(1 - sSum)

This is s1

Cse536 Functional Programming

3104/18/23

Assignment #3, Also in the assignments web page

Be sure and include a listing (1-2 pages) which shows how you tested your programs in the Hugs system.

1) Write a function "wordsL" such that (wordsL "This is a sentence.") returns ["This", "is","a","sentence."]. It breaks a string into a list of strings. It breaks the strings (and throws away the separators) at blanks ( ' ' ), tabs ( '\t' ), and newlines ( '\n' ). Hint: takeWhile and dropWhile are very useful.

e.g. (takeWhile even [2,4,5,6,7]) => [2,4]. There is a function called words in the prelude that does exactly this. Write your own version.

2) Exercise 3.1 page 49 of the text

3) Use the IO monad to write a function when given two strings as input, opens a file with the first strings name, and copys it to another file, with the name of the second string. copy :: String -> String -> IO () . Be sure and test your function in the input you hand in.

4) Write a program "pal" which reads a string from the user, and then prints on the screen if that string is a palindrome. (A palindrome is a string which reads the same both forwards and backwards. For example "hah" and "abCba".) pal :: IO ()

5) Using the primitive drawing functions of chapter 4 of the text, open a graphics window and draw a picture of a "house".