• No results found

Introduction FUNCTIONAL PROGRAMMING. The Problem. The Solution. Graham Hutton. Lecture 9 - Interactive Programs. keyboard. screen

N/A
N/A
Protected

Academic year: 2021

Share "Introduction FUNCTIONAL PROGRAMMING. The Problem. The Solution. Graham Hutton. Lecture 9 - Interactive Programs. keyboard. screen"

Copied!
26
0
0

Loading.... (view fulltext now)

Full text

(1)

1

FUNCTIONAL PROGRAMMING

Graham Hutton

Lecture 9 - Interactive Programs

1

Introduction

To date, we have seen how Haskell can be used to write batch programs that take all their inputs at the start and give all their outputs at the end.

batch program

inputs outputs

2

However, we would also like to use Haskell to write interactive programs that read from the keyboard and write to the screen, as they are running.

interactive program

inputs outputs

keyboard

screen

3

The Problem

Haskell programs are pure mathematical functions:

However, reading from the keyboard and writing to the screen are side effects:

 Haskell programs have no side effects.

 Interactive programs have side effects.

4

The Solution

Interactive programs can be written in Haskell by using types to distinguish pure expressions from impure actions that may involve side effects.

IO a

The type of actions that return a value of type a.

5

For example:

IO Char

IO ()

The type of actions that return a character.

The type of purely side effecting actions that return no result value.

 () is the type of tuples with no components.

Note:

(2)

2

6

Primitive Actions

The standard library provides a number of actions, including the following three primitives:

getChar :: IO Char

 The action getChar reads a character from the keyboard, echoes it to the screen, and returns the character as its result value:

7

 The action putChar c writes the character c to the screen, and returns no result value:

putChar :: Char → IO ()

 The action return v simply returns the value v, without performing any interaction:

return :: a → IO a

8

A sequence of actions can be combined as a single composite action using the keyword do.

For example:

Sequencing Actions

getTwo :: IO (Char,Char) getTwo = do x ← getChar

y ← getChar return (x,y)

9

Note - in a sequence of actions:

 Each action must begin in precisely the same column. That is, the layout rule applies.

 The values returned by intermediate actions are discarded by default, but if required can be named using the ← operator.

 The value returned by the last action is the value returned by the sequence as a whole.

10

Other Library Actions

getLine :: IO String getLine = do x ← getChar

if x == '\n' then return []

else

do xs ← getLine return (x:xs)

 Reading a string from the keyboard:

11

putStr :: String → IO () putStr [] = return () putStr (x:xs) = do putChar x

putStr xs

 Writing a string to the screen:

 Writing a string and moving to a new line:

putStrLn :: String → IO () putStrLn xs = do putStr xs

putChar '\n'

(3)

3

12

Example

We can now define an action that prompts for a string to be entered and displays its length:

strlen :: IO ()

strlen = do putStr "Enter a string: "

xs ← getLine

putStr "The string has "

putStr (show (length xs)) putStrLn " characters"

13

For example:

> strlen

Enter a string: hello there The string has 11 characters

 Evaluating an action executes its side effects, with the final result value being discarded.

Note:

14

Hangman

Consider the following version of hangman:

 One player secretly types in a word.

 The other player tries to deduce the word, by entering a sequence of guesses.

 For each guess, the computer indicates which letters in the secret word occur in the guess.

15

 The game ends when the guess is correct.

hangman :: IO () hangman =

do putStrLn "Think of a word: "

word ← sgetLine

putStrLn "Try to guess it:"

guess word

We adopt a top down approach to implementing hangman in Haskell, starting as follows:

16

The action sgetLine reads a line of text from the keyboard, echoing each character as a dash:

sgetLine :: IO String sgetLine = do x ← getCh

if x == '\n' then do putChar x

return []

else

do putChar '-' xs ← sgetLine return (x:xs)

17

primitive getCh :: IO Char Note:

 The action getCh reads a character from the keyboard, without echoing it to the screen.

 This useful action is not part of the standard library, but is a special Hugs primitive that can be imported into a script as follows:

(4)

4

18

The function guess is the main loop, which requests and processes guesses until the game ends.

guess :: String → IO () guess word =

do putStr "> "

xs ← getLine if xs == word then

putStrLn "You got it!"

else

do putStrLn (diff word xs) guess word

19

The function diff indicates which characters in one string occur in a second string:

For example:

> diff "haskell" "pascal"

"-as--ll"

diff :: String → String → String diff xs ys =

[if elem x ys then x else '-' | x ← xs]

20

If you would like to try out the hangman game for yourself, it is available on our Unix machines:

% hugs ~gmh/Teaching/FUN/Source/hangman.hs

> hangman

Think of a word:

---

Try to guess it:

> pascal -as--ll

> haskell You got it!!

21

Exercise

Implement the game of nim in Haskell, where the rules of the game are as follows:

 The board comprises five rows of stars:

1: * * * * * 2: * * * * 3: * * * 4: * * 5: *

22

 Two players take it turn about to remove one or more stars from the end of a single row.

 The winner is the player who removes the last star or stars from the board.

Hint:

Represent the board as a list of five integers that give the number of stars remaining on each row.

For example, the initial board is [5,4,3,2,1].

(5)

 )81&7,21$/352*5$00,1*

*UDKDP+XWWRQ

/HFWXUH'HILQLQJ7\SHV



7\SH'HFODUDWLRQV

,Q+DVNHOODQHZQDPHIRUDQH[LVWLQJW\SHFDQEH GHILQHGXVLQJDW\SHGHFODUDWLRQ

W\SH6WULQJ >&KDU@

6WULQJLVDV\QRQ\PIRUWKHW\SH>&KDU@



7\SHGHFODUDWLRQVFDQEHXVHGWRPDNHRWKHUW\SHV HDVLHUWRUHDG)RUH[DPSOHJLYHQ

RULJLQ3RV RULJLQ  

OHIW3RV→3RV OHIW [\   [\

W\SH3RV  ,QW,QW ZHFDQGHILQH



/LNHIXQFWLRQGHILQLWLRQVW\SHGHFODUDWLRQVFDQDOVR KDYHSDUDPHWHUV)RUH[DPSOHJLYHQ

W\SH3DLUD  DD

ZHFDQGHILQH

ELWV3DLU,QW ELWV  

FRS\D→3DLUD FRS\[  [[



7\SHGHFODUDWLRQVFDQEHQHVWHG

W\SH3RV  ,QW,QW W\SH7UDQV 3RV→3RV

+RZHYHUWKH\FDQQRWEHUHFXUVLYH

W\SH7UHH  ,QW>7UHH@



'DWD'HFODUDWLRQV

$QHZW\SHFDQEHGHILQHGE\VSHFLI\LQJLWVVHWRI YDOXHVXVLQJDGDWDGHFODUDWLRQ

GDWD%RRO )DOVH_7UXH

%RROLVDQHZW\SHZLWKWZR QHZYDOXHV)DOVHDQG7UXH

(6)





1RWH

❚ 7KHWZRYDOXHV)DOVHDQG7UXHDUHFDOOHGWKH FRQVWUXFWRUVIRUWKHW\SH%RRO

❚ 7\SHDQGFRQVWUXFWRUQDPHVPXVWEHJLQZLWK DQXSSHUFDVHOHWWHU

❚ 'DWDGHFODUDWLRQVDUHVLPLODUWRFRQWH[WIUHH JUDPPDUV7KHIRUPHUVSHFLILHVWKHYDOXHVRI DW\SHWKHODWWHUWKHVHQWHQFHVRIDODQJXDJH



DQVZHUV>$QVZHU@

DQVZHUV ><HV1R8QNQRZQ@

IOLS$QVZHU→$QVZHU IOLS<HV 1R

IOLS1R <HV IOLS8QNQRZQ 8QNQRZQ

GDWD$QVZHU <HV_1R_8QNQRZQ ZHFDQGHILQH

9DOXHVRIQHZW\SHVFDQEHXVHGLQWKHVDPHZD\V DVWKRVHRIEXLOWLQW\SHV)RUH[DPSOHJLYHQ



7KHFRQVWUXFWRUVLQDGDWDGHFODUDWLRQFDQDOVRKDYH SDUDPHWHUV)RUH[DPSOHJLYHQ

GDWD6KDSH &LUFOH)ORDW

_5HFW)ORDW)ORDW

VTXDUH6KDSH VTXDUH 5HFW

DUHD6KDSH→)ORDW DUHD &LUFOHU  SL UA

DUHD 5HFW[\  [ \

ZHFDQGHILQH



1RWH

❚ 6KDSHKDVYDOXHVRIWKHIRUP&LUFOHUZKHUHULV DIORDWDQG5HFW[\ZKHUH[DQG\DUHIORDWV

❚ &LUFOHDQG5HFWFDQEHYLHZHGDVIXQFWLRQVWKDW VLPSO\FRQVWUXFWYDOXHVRIW\SH6KDSH

&LUFOH)ORDW→6KDSH

5HFW)ORDW→)ORDW→6KDSH



1RWVXUSULVLQJO\GDWDGHFODUDWLRQVWKHPVHOYHVFDQ DOVRKDYHSDUDPHWHUV)RUH[DPSOHJLYHQ

GDWD0D\EHD 1RWKLQJ_-XVWD

]HUR0D\EH,QW ]HUR -XVW

DSS D→E →0D\EHD→0D\EHE DSSI1RWKLQJ 1RWKLQJ

DSSI -XVW[  -XVW I[

ZHFDQGHILQH



5HFXUVLYH7\SHV

,Q+DVNHOOQHZW\SHVFDQEHGHILQHGLQWHUPVRI WKHPVHOYHV7KDWLVW\SHVFDQEHUHFXUVLYH

GDWD1DW =HUR_6XFF1DW

1DWLVDQHZW\SHZLWKFRQVWUXFWRUV

=HUR1DWDQG6XFF1DW1DW

(7)





1RWH

❚ $YDOXHRIW\SH1DWLVHLWKHU=HURRURIWKHIRUP 6XFFQZKHUHQ1DW7KDWLV1DWFRQWDLQVWKH IROORZLQJLQILQLWHVHTXHQFHRIYDOXHV

=HUR 6XFF=HUR

6XFF 6XFF=HUR



❚ :HFDQWKLQNRIYDOXHVRIW\SH1DWDVQDWXUDO QXPEHUVZKHUH=HURUHSUHVHQWVDQG6XFF UHSUHVHQWVWKHVXFFHVVRUIXQFWLRQ  

❚ )RUH[DPSOHWKHYDOXH

6XFF 6XFF 6XFF=HUR UHSUHVHQWVWKHQDWXUDOQXPEHU

   



8VLQJUHFXUVLRQLWLVHDV\WRGHILQHIXQFWLRQVWKDW FRQYHUWEHWZHHQYDOXHVRIW\SH1DWDQG,QW

QDWLQW1DW→,QW QDWLQW=HUR 

QDWLQW 6XFFQ  QDWLQWQ

LQWQDW,QW→1DW LQWQDW =HUR

LQWQDW Q  6XFF LQWQDWQ



7ZRQDWXUDOVFDQEHDGGHGE\FRQYHUWLQJWKHPWR LQWHJHUVDGGLQJDQGWKHQFRQYHUWLQJEDFN

+RZHYHUXVLQJUHFXUVLRQWKHIXQFWLRQDGGFDQEH GHILQHGZLWKRXWWKHQHHGIRUFRQYHUVLRQV

DGG1DW→1DW→1DW

DGGPQ LQWQDW QDWLQWPQDWLQWQ

DGG=HURQ Q

DGG 6XFFP Q 6XFF DGGPQ 



)RUH[DPSOH

DGG 6XFF 6XFF=HUR  6XFF=HUR 6XFF DGG 6XFF=HUR  6XFF=HUR 6XFF 6XFF DGG=HUR 6XFF=HUR 6XFF 6XFF 6XFF=HUR

1RWH

❚ 7KHUHFXUVLYHGHILQLWLRQIRUDGGFRUUHVSRQGVWR WKHODZVQ QDQG P Q  PQ 



$ULWKPHWLF([SUHVVLRQV

&RQVLGHUDVLPSOHIRUPRIH[SUHVVLRQVEXLOWXSIURP LQWHJHUVXVLQJDGGLWLRQDQGPXOWLSOLFDWLRQ









(8)





8VLQJUHFXUVLRQDVXLWDEOHQHZW\SHWRUHSUHVHQW VXFKH[SUHVVLRQVFDQEHGHILQHGE\

)RUH[DPSOHWKHH[SUHVVLRQRQWKHSUHYLRXVVOLGH ZRXOGEHUHSUHVHQWHGDVIROORZV

GDWD([SU 9DO,QW

_$GG([SU([SU

_0XO([SU([SU

$GG 9DO  0XO 9DO  9DO



8VLQJUHFXUVLRQLWLVQRZHDV\WRGHILQHIXQFWLRQV WKDWSURFHVVH[SUHVVLRQV)RUH[DPSOH

VL]H([SU→,QW VL]H 9DOQ  

VL]H $GG[\  VL]H[VL]H\

VL]H 0XO[\  VL]H[VL]H\

HYDO([SU→,QW HYDO 9DOQ  Q

HYDO $GG[\  HYDO[HYDO\

HYDO 0XO[\  HYDO[ HYDO\



1RWH

❚ 7KHWKUHHFRQVWUXFWRUVKDYHW\SHV

9DO,QW→([SU

$GG([SU→([SU→([SU 0XO([SU→([SU→([SU

❚ 0DQ\IXQFWLRQVRQH[SUHVVLRQVFDQEHGHILQHG E\UHSODFLQJWKHFRQVWUXFWRUVE\RWKHUIXQFWLRQV XVLQJDVXLWDEOHIROGIXQFWLRQ)RUH[DPSOH

HYDO IROGLG  



%LQDU\7UHHV

,QFRPSXWLQJLWLVRIWHQXVHIXOWRVWRUHGDWDLQD WZRZD\EUDQFKLQJVWUXFWXUHRUELQDU\WUHH

















8VLQJUHFXUVLRQDVXLWDEOHQHZW\SHWRUHSUHVHQW VXFKELQDU\WUHHVFDQEHGHILQHGE\

)RUH[DPSOHWKHWUHHRQWKHSUHYLRXVVOLGHZRXOG EHUHSUHVHQWHGDVIROORZV

GDWD7UHH /HDI,QW

_1RGH7UHH,QW7UHH

1RGH 1RGH /HDI  /HDI



 1RGH /HDI  /HDI



:HFDQGHILQHDIXQFWLRQILQGWKDWGHFLGHVLIDJLYHQ LQWHJHURFFXUVLQDELQDU\WUHH

ILQG,QW→7UHH→%RRO ILQG[ /HDIQ  [ Q

ILQG[ 1RGHOQU  [ Q

__ILQG[O

__ILQG[U +RZHYHUWKLVIXQFWLRQVLPSO\WUDYHUVHVWKHHQWLUH WUHHDQGKHQFHIRURXUH[DPSOHWUHHPD\UHTXLUH XSWRVHYHQFRPSDULVRQVWRSURGXFHDUHVXOW

(9)





1RZFRQVLGHUWKHIXQFWLRQIODWWHQWKDWUHWXUQVWKH OLVWRIDOOWKHLQWHJHUVFRQWDLQHGLQDWUHH

IODWWHQ7UHH→>,QW@

IODWWHQ /HDIQ  >Q@

IODWWHQ 1RGHOQU  IODWWHQO

>Q@

IODWWHQU

$WUHHLVDVHDUFKWUHHLILWIODWWHQVWRDOLVWWKDWLV RUGHUHG2XUH[DPSOHWUHHLVDVHDUFKWUHHDVLW IODWWHQVWRWKHRUGHUHGOLVW>@



6HDUFKWUHHVKDYHWKHLPSRUWDQWSURSHUW\WKDWZKHQ WU\LQJWRILQGDYDOXHLQDWUHHZHFDQDOZD\VGHFLGH ZKLFKRIWKHWZRVXEWUHHVLWPD\RFFXULQ

)RUH[DPSOHWU\LQJWRILQGDQ\YDOXHLQRXUVHDUFK WUHHRQO\WDNHVDWPRVWWKUHHFRPSDULVRQV

ILQG[ /HDIQ  [ Q ILQG[ 1RGHOQU _[ Q 7UXH

_[Q ILQG[O

_[!Q ILQG[U



([HUFLVHV

 8VLQJUHFXUVLRQDQGWKHIXQFWLRQDGGGHILQHD IXQFWLRQWKDWPXOWLSOLHVWZRQDWXUDOQXPEHUV

 'HILQHDVXLWDEOHIXQFWLRQIROGIRUH[SUHVVLRQV

DQGJLYHDIHZH[DPSOHVRILWVXVH

 $ELQDU\WUHHLVFRPSOHWHLIWKHWZRVXEWUHHVRI HYHU\QRGHDUHRIHTXDOVL]H'HILQHDIXQFWLRQ WKDWGHFLGHVLIDELQDU\WUHHLVFRPSOHWH

(10)

1 FFF FU U U UN N N NC C C CTT TIIIIO T ON O O NA N N ALLL A A L

P P P

PR R R RO O O OG G G GR RA R R AM A A MM M M M M MIIIIN N N NG G G G

Bernhard Reus

Lecture 11 - Basic Graphics

1

The Hugs Graphics Library

❚ GraphicsUtils.hs works within Hugs

❚ Written by Alastair Reid, University of Utah

❚ Library compatible with Win32 and X11

❚ Graphics as Input/Output

❚ Embedded in Haskell IO type

2

A First Example

helloWorld :: IO ()

helloWorld = runGraphics (

do w <- openWindow "Hello World Window"

(300,300)

drawInWindow w (text (100,100) "Hello") drawInWindow w (text (100,200) "World") getKey w

closeWindow w )

Open a window, print "Hello World" in it and close the window as soon as the user releases a key.

3

Example on Screen

4

❚ As graphics are IO one can use the do syntax for sequences of Graphic actions

runGraphics :: IO () -> IO ()

prepares Hugs for graphics, runs argument and cleans up.

opens a window with given title and size and returns it

openWindow :: Title -> Size -> IO Window

5

text :: Point -> String -> Graphic

drawInWindow :: Window -> Graphic -> IO ()

produces a graphic that consists of the given string printed at given coordinates.

Point specifies top-left corner draws a graphic object in a given window

(11)

2

6

Size and Point are types defined as follows type Size = (Int,Int)

type Point = (Int,Int)

waits for user to press and release a key and returns corresponding character getKey :: Window -> IO Char

width and height x and y-coordinates

closeWindow :: Window -> IO () closes given window

7

Graphic Library Overview

❚ Window: draw in it a Graphic, check for Events.

❚ Graphic: built by drawing figures or text:

line, polygon, polyline, ellipse, arc or text.

Graphics can be stacked with overGraphic.

❚ Graphic modifiers to change

Color, Pen, Brush, Font, background.

❚ Event handling: events are

Char, Key, MouseMove, Button (of mouse).

8

Overview (cont’d)

❚ Event handling explicit and no Listeners as in Java.

❚ No complex container objects as in Java API.

❚ For more detailed information consult

"The Hugs Graphics Library" document on the course webpage.

❚ Do not forget to import GraphicsUtils before use.

9

openWindow :: Title -> Size -> IO Window closeWindow :: Window -> IO ()

clearWindow :: Window -> IO () getGraphic :: Window -> IO Graphic setGraphic :: Window -> Graphic -> IO () drawInWindow :: Window -> Graphic -> IO ()

Windows

open, close, and clearWindow do the obvious.

getGraphic returns the graphic of a window and setGraphic prints a graphic (overriding).

drawInWindow prints over the given graphic.

10

Windows (cont’d)

getWindowRect :: Window -> IO (Point,Point)

getWindowEvent :: Window -> IO Event gets window parameters: location and size as points. Useful when the window has been resized or moved.

gets next window event

11

Atomic Graphics

text :: Point -> String -> Graphic

line :: Point -> Point -> Graphic draws a given string at a given point

draws a line between two points polygon :: [Point] -> Graphic

draws a filled polygon through points in list

(12)

3

12

Atomic Graphics

ellipse :: Point -> Point -> Graphic draws an unfilled elliptical arc

in rectangle defined by two points with two angles (in degrees) as shown beneath:

draws a filled ellipse inside given rectangle arc :: Point -> Point -> Angle -> Angle

-> Graphic

angle2 angle1

13

Graphics & Modifiers

withColor :: Color -> Graphic -> Graphic puts first graphic on top of second

produces that graphic in given colour

overGraphic :: Graphic -> Graphic -> Graphic

withTextAlignment :: Alignment -> Graphic

-> Graphic

produces text in graphic in given alignment

14

Modifier Types

type Alignment = (HAlign,VAlign) type HAlign = Left’ | Center | Right’

type VAlign = Top | Baseline | Bottom Colour names

type Color =

Black | Blue | Green | Cyan | Red | Magenta | Yellow | White

Alignment names. Default = (Left’,Top)

15

Example

hw :: IO () hw = runGraphics (

do w <- openWindow "Hello World Window"

(300,300)

drawInWindow w (text (100,100) "Hello") drawInWindow w (withColor Blue

(text (100,200) "World")) drawInWindow w (withColor Magenta

(polygon [(100,60),(70,50),(100,20)])) getKey w

closeWindow w )

16

Example Comments

❚ “Hello World” with “World” in blue

❚ Magenta polygon with three nodes

= triangle

17

Events: how to get them

❚ In a nonterminating loop trace all events in a window and print them on the screen:

tracer:: IO ()

tracer = runGraphics (

do w <- openWindow "Event Tracer"

(300,300) loop w )

where loop w = do e <- getWindowEvent w putStrLn (show e) loop w

(13)

4

18

❚ Close the window by using the window menu or typing <ALT><F4>.

❚ show also works for events and transforms them into strings.

❚ We can mix graphic actions with our old IO actions as they are both of type IO a .

19

Event types

❚ Boolean parameters:

Key : is key down? (or released)

Button: is left (or right) mouse button pressed?

is button down? (or released) data Event =

Char Char

| Key Key Bool

| Button Point Bool Bool

| MouseMove Point

| Resize

| Closed

Meaning Character pressed key pressed

mouse button pressed mouse moved to point window resized window closed

20

Key Event types

❚ Note that types and constructors may have the same name (Char, Key)

❚ Special keys can be checked using predicates like: isDeleteKey :: Key -> Bool

isEscapeKey :: Key -> Bool isShiftLKey :: Key -> Bool isShiftRKey :: Key -> Bool isControlLKey :: Key -> Bool isControlRKey :: Key -> Bool … and so on.

21

Event Example

A simple program that prints red crosses (Xs) where you move the mouse.

If a character key is hit the character is printed in yellow in the middle of the window. Hitting the Escape-key closes the window.

22

crazy :: IO () crazy = runGraphics (

do w <- openWindow "Move Mouse" (300,300) loop w )

loop :: Window -> IO ()

loop w = do e <- getWindowEvent w handleEvent w e

❚ Open the window and start the event loop.

❚ The handler is a separate function (could be made local using where).

23

Events: can you handle them?

handleEvent :: Window -> Event -> IO () handleEvent w (MouseMove (x,y)) = do drawInWindow w

(withColor Red (text (x,y) "X")) loop w

handleEvent w (Char c) = do drawInWindow w

(withColor Black (polygon [(150,150),(150,170), (170,170),(170,150)] )) drawInWindow w (withColor Yellow

(text (150,150) [c])) loop w

(14)

5

24

handleEvent w (Key a True) =

if isEscapeKey a

then closeWindow w else loop w handleEvent w _ = loop

❚ Pattern matching can be used for Event argument in an event handler definition.

❚ Deletion of text is done by drawing a rectangle in background colour.

❚ One has to “catch” also the events one is not interested in or the program will abort.

25

Exercises

Write a program that opens a window (of appropriate size) and draws a red square of length 100 pixels and a blue circle of radius 50 pixels next to each other.

Swap the colours of the graphics when a mouse button has been pressed and close the window when the left Shift key has been pressed.

(1)

(2)

26

Write a program that opens a window, waits for the user to type printable characters on the keyboard and echoes them in the window (as long as there is space). If the left mouse button is pressed the content of the window is erased and printing starts again in the top left corner. The right button closes the window.

Assume that characters have width 9 pixels and height 14 pixels.

(3)

(15)

1 FUNCTIONAL PROGRAMMING

Bernhard Reus

Lecture 12 - Modules

1

Modules

!For bigger projects Haskell scripts should be structured and split into modules.

!A module consists of type, function, and object definitions with a clearly defined interface.

!Interfaces state what is exported and what is imported.

1

Advantages of Modules

!separate development

!separate compilation

!re-usability (libraries)

!reduce complexity

1

Module Headers

Syntax for module is as follows:

module <Name> where

<list of definitions>

!<Name>must start with an uppercase letter and is the module’s name. The file itself must be called <Name>.hs.

!The <list of definitions>contains definitions in the usual way. They describe the entities defined in the module.

1

module Gui where

type Point = (Int,Int)

movePoint:: Point -> Int -> Point movePoint (x,y) z = (x+z,y+z) For example, consider a file Gui.hs:

After loading Gui.hsHugs will change its prompt indicating that evaluation now is w.r.t. the definitions in module Gui.

Gui>

1

Import

The importclause allows one to import other modules’ definitions:

module Gui where import GraphicsUtils import MyOtherModule

data Shape = Rect Point Point

| Circle Int

drawShape:: Window -> Shape -> Graphic drawShape w (Rect p1 p2) = …

drawShape w (Circle n) = …

(16)

2

1

Import Caveats

!Obey layout rule with respect to import keyword.

!Avoid cyclic imports.

!Make sure that the .hs file containing your module has the right name (that is the same name).

1

Export Controls

module Gui (Shape (..),drawShape) where import GraphicsUtils

data Shape = … drawShape :: …

!By default a module exports all the definitions it contains but not the imported ones.

!This can be changed by explicitly providing an export list:

1

!The export list contains the names of the exported objects and types. The list is written in parentheses and names are separated by commas.

!Shape (..)indicates that the type Shapewith its constructors is exported.

!To export a whole module write:

module Gui (module GraphicsUtils) where…

1

!Therefore, the following two definitions are equivalent:

!Other example:

module Gui (module Gui) where…

module Gui where…

module Gui (module Gui, module Prelude) where…

1

Name Clashes

!If files are imported then there is always the danger of name clashes. For example,

!To avoid name clashes one can control the import list:

module A where import B f x = x + 3

module B where f xs = “foo” ++ xs g = map f

1

Import Controls

!Like export lists one can also define import lists explicitly. For example:

!Only the names in the list (in parentheses, separated by commas) are imported.

!In the definition of g, fstill refers to the fof B. module A where

import B (g) f x = x + 3

module B where f xs = “foo” ++ xs g = map f

(17)

3

1

Shadowing

!Hiding names that can be used for other definitions is also called shadowing.

!Keyword hidingallows one to shadow several names and import all the rest:

!Again, the list of names can contain types and names are separated by commas.

module A where import B hiding (f) f x = x + 3

1

Qualified Names

!What if one likes to use both functions named f in modules A and B? How can the name clash be resolved then?

!Use qualified names.

!A qualified name is built from the name of a module and the name of an object in that module. For example:

A.f B.f

1

Qualified Import

!Use keyword qualifiedto make imported names qualified. For example:

!Qualified import can be combined with all the other features of import lists.

module A where import qualified B

f x = x +3 g = map B.f

1

!In export lists there must not be any name clashes.

!Attention: A qualifier in a name identifies the module an entity is imported from, not the module it is defined in. For example:

!Name clash if one imports from Aas B.fand C.f are both referenced outside Aas A.f (not A.B.fand A.C.f).

module A (B.f, C.f) where import qualified B(f) import qualified C(f) …

1

!Modules must be closed. Any name mentioned in the module must be defined in the source or imported from another module.

!Instance declarations are exported and imported automatically.

1

Abstract Data Types

!Information Hiding.

!Do not give away implementation details to users of your module.

!Example: Sets.

If there is an implementation of sets by lists how can that implementation be hidden?

(18)

4

1

Abstract Data Type Set

!Use the export mechanism to hide information:

module Set (Set,empty,single,union,meet) where

data Set a = S [a]

empty = S []

single x = S [x]

union (S xs)(S ys) = S (elimDoubles (xs++ys)) meet (S xs)(S ys) =

S (elimDoubles [x| x <- xs, elem x ys])

1

!Note that the constructor Sfor type Setis not exported.

!Therefore, the only way to construct sets in another module is by using exported functions empty, single, union, and meet.

!Modules that provide the same export list are interchangeable (if the types of the entities match)

!No “implements” like in Java.

1

How to use Modules

!Modules should implement one specific task only and completely.

!Modules should be small.

!Modules should be as general as possible to support re-usability.

!Modules should only export what is absolutely necessary (information hiding).

1

Exercises

Put your solutions of previous exercise sheets in modules.

Complete the module Setgiving a definition for elimDoublesand write another module MySet that provides all the set functions where union is changed to have three arguments. All those functions but the binary union should be exported. Import them in a module C where you define some sets using union and single.

(1)

(2)

1

(3) Write an abstract data type Stack that uses lists as data representation, Implement the following stack operations:

emptyS:: Stack a

push :: a -> Stack a -> Stack a pop :: Stack a -> Stack a

(19)

1 FFF FU U U UN N N NC C C CTT TIIIIO T ON O O NA N N ALLL A A L

P P P

PR R R RO O O OG G G GR RA R R AM A A MM M M M M MIIIIN N N NG G G G

Bernhard Reus

Lecture 13 - Classes

1

Type Classes

❚ Type classes are a means for defining overloading in a clear and structured way.

❚ Type classes appear as constraints in types of overloaded functions.

❚ Several type classes are built-in, for example:

Ord, Eq, Num.

❚ This lecture explains how user-defined classes can be done and how they work.

2

Overloaded Functions

(==) :: Eq a => a -> a -> Bool (<=) :: Ord a => a -> a -> Bool (+) :: Num a => a -> a -> a show :: Show a => a -> String

Class constraint

Different implementations of overloaded functions provided in different types.

3

Class & Instance

❚ A class is the collection of types over which an overloaded function is defined.

❚ The members (types) of a class are called instances.

❚ For example, instances of Eq are: Int, Bool, String, Float, but also (Int,Char), [Char], [[Char]], [(Char,Char)], and so on.

Thus, (==) works for all instances of Eq.

4

How to Define a Class

A signature is a list of function names with their types. To write down these types, a type variable is used that represents the possible instances. For example:

class <Name> <TypeVar> where

<signature involving <TypeVar>>

class Eq a where (==) :: a -> a -> Bool

5

How to Define an Instance

The definitions of the functions refer now to the specified type that replaces the type variable in the class definition. Example:

instance <ClassName> <Type> where

<definition of functions in the signature of <ClassName>>

instance Eq Bool where True == True = True True == False = False False == True = False False == False = True

(20)

2

6

❚ For built-in numeric types like Float and Int etc., instance definitions refer to appropriate primitive equality definitions provided as native code by the compiler.

❚ For user defined classes functions are defined as usual (using pattern matching etc.).

❚ Classes can contain default implementations.

❚ Classes can depend on other classes and instances can depend on other instances.

7

Default Implementations

.

class Eq a where

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

Default implementations can be overridden by instance definitions.

8

Derived Classes

Class definitions may depend on other classes.

For example:

class Eq a => Ord a where

(<),(<=),(>),(>=) :: a -> a -> Bool max, min :: a -> a -> a

9

❚ This means that an instance of Ord must not only provide the functions of Ord’s signature but also of Eq’s signature.

❚ The functions of Eq can then be used to implement the functions of Ord.

❚ Ord is inheriting operations from Eq.

10

❚ Type a cannot appear in a (class) context not mentioned in the instance declaration.

class Eq a => ShowEq a where ifS :: Show a => a -> a -> String foo :: Show b => b -> (String,a)

class (Eq a,Show a) => ShowEq a where

ifS :: a -> a -> String

foo :: Show b => b -> (String,a)

11

Multiple Inheritance

Here the operation (==) from Eq and show form Show have been inherited.

Several contexts can be used (more than two).

class (Eq a,Show a) => ShowEq a where

ifS :: a -> a -> String ifS x y = if x==y then “tie”

else show x

(21)

3

12

Derived Instances

Compound types may be instances of classes if constituent types are instances of the same class.

For example:

instance Eq a => Eq [a] where [] == [] = True

(x:xs) == (y:ys) = x==y && (xs==ys) equality of type a

13

❚ So the equality on a list depends on the equality on the elements of the list.

❚ Similar for tuple types.

❚ Also here multiple constraints may appear. For example:

instance (Eq a, Eq b) => Eq (a,b) where

(x1,y1) == (x2,y2) = x1==x2 && y1==y2

14

Data Types as Class Instances

For data types there is a special syntax to declare them as instances of a certain class:

data Tree a = Leaf a

| Node (Tree a) a (Tree a) deriving (Eq,Ord,Show,Read)

Tree is an instance of classes Eq, Ord, Show, and Read.

list of classes the type is an instance of

15

❚ Keyword deriving indicates the following implicit instance declarations.

❚ You can only use the following classes:

Eq, Ord, Show, Enum, Read

as for others the instances cannot be computed automatically.

❚ Ord defines a lexicographic ordering on the data type.

16

❚ Constructors are ordered by order of appearance. For example

(Leaf 30) < (Node (Leaf 1) 1 (Leaf 2)) (Leaf 3) < (Leaf 11)

❚ Class Show allows usage of function show : a -> String

which converts a value into a string.

> show (Node (Leaf 1) 1 (Leaf 2))

“Node (Leaf 1) 1 (Leaf 2)”

17

❚ Read is the opposite of Show and allows one to parse values of the given type from a string.

❚ The function it provides is:

❚ This parser works for all values of Haskell types in Haskell syntax. Note that the string must be completely consumed by the parser.

read :: Read a => String -> a

(22)

4

18

> read ”34” + 3 37

> head (read “[1,2]”) + 3 4

> read “34xx” + 3

Program error Prelude. read no parse

Examples for Read

19

Enumeration Types

❚ If all constructors are nullary then this defines an enumeration type and one can declare it to be an instance of class Enum. For example:

data Car = Ford | Jag | Merc | Porsche deriving (Show,Read,Ord,Eq,Enum)

declares an enumeration type

> [Jag .. ] [Jag,Merc,Porsche]

space important here

20

Higher-Order Classes

❚ Classes can not only be defined on types, but also on type constructors.

❚ Type constructors are for example:

function space, lists, tuples, triples etc.

❚ An example is the monad class Monad a.

(->), [], (,), (,,)

21

❚ One can declare an instance of the list monad like this:

❚ This is already done in Prelude.

❚ One can not declare a type alias defined via type N a = … as instance of a class.

instance Monad [] where return t = [t]

xs >>= f = concat (map f xs)

22

Comparison with OOP

❚ In Haskell and OOP classes capture a common set of operations.

❚ In both cases we have instances, inheritance, default implementations and overriding.

❚ In Haskell instances are types that have no mutable state. Correspondingly, it can be computed at compile time which overloaded operation is used.

23

Kinds of Polymorphism

❚ Subtype polymorphism in OOP. Which operation is called depends on dynamic type of object.

❚ Generic (parametric) polymorphism in Haskell combined with overloading in a neat way. Type classes provide smaller “universes” of types.

f :: a -> Bool f :: C a => a -> Bool

possible instances of a:

all types in class C all types

(23)

1 FFF FU U U UN N N NC C C CTT TIIIIO T ON O O NA N N ALLL A A L

P P P

PR R R RO O O OG G G GR RA R R AM A A MM M M M M MIIIIN N N NG G G G

Bernhard Reus

Lecture 14 - Lazy Evaluation

1

Lazy Evaluation…

❚ … denotes a certain evaluation strategy that only evaluates an expression when the result is needed.

❚ … allows for infinite data structures.

❚ … supports a more abstract programming style

❚ Most other languages are eager.

2

Lazy Function Application

❚ Recall the boolean operator (&&) that only evaluates its second argument if the first one was True.

❚ One can test whether an argument of a function is evaluated by applying the function to

undefined:

> False && undefined False

> undefined && True Program error: {undefined}

3

❚ Arguments of functions are evaluated by need.

❚ If an argument has to be evaluated, however, then it is evaluated just once.

For example in

(2+3) is evaluated only once and (12^2) never.

f x y = x + x + x

>f (2+3) (12^2) 15

4

Lazy Data Structures

❚ If a structured element like

* a tuple (s,t)

* a list x:xs

* a value of a datatype C(t1,…tn)

is evaluated then only those parts are evaluated that are really needed.

❚ For example, in

the argument list is only evaluated until its head element is known.

> head (1:undefined) 1

5

Infinite Data Structures

❚ Since evaluation is lazy, values of data types can be infinite by recursion.

❚ For example, this recursive definition of a list

defines an infinite list of 1s.

xs :: [Int]

xs = 1:xs

> xs

[1,1,1,1,1,1,1,^C {Interrupted}

(24)

2

6

xs 1:xs

=

1:(1:xs)

=

1:(1:(1:xs))

=

[1,1,1,1,1,1,1,1,1,…

= Evaluation of

yields

> xs

7

Evaluation of

take 2 xs take 2 (1:xs)

=

1:(take 1 xs)

=

1:(take 1 (1:xs))

=

1:1:(take 0 xs)

= yields

> take 2 xs

1:1:[] = [1,1]

=

8

Sieve of Eratosthenes

This algorithm, over 2000 years old, computes the list of prime numbers.

Idea:

2 3 4 5 6 7 8 9 10 11 12 13 …

❚ Start with a list of all numbers but 1.

❚ Once a prime number is found cancel out all its multiples.

9

2 3 4 5 6 7 8 9 10 11 12 13 … 2 3 4 5 6 7 8 9 10 11 12 13 …

2 3 4 5 6 7 8 9 10 … 14 15 … 2 3 4 5 6 7 8 9 10 11 12 13 …

2 3 4 5 6 7 8 9 10 … 14 15 …

10

Sieve Algorithm

❚ Start with a list of all numbers but 1.

❚ The head of the list is a prime number.

❚ Cancel out all multiples of the head in the rest list.

❚ Repeat that algorithm for the new rest list.

sieve :: [Int] -> [Int]

sieve (x:xs) =

x:(sieve [y | y <- xs, y `mod` x > 0]) prime :: [Int]

prime = sieve [2..]

11

Evaluation of

prime sieve [2..]

=

2:(sieve [y| y<-[3..], y`mod`2 > 0])

=

2:(sieve (3:[y| y<-[4..], y`mod`2 > 0]))

=

2:3:(sieve [z|z<-[y|y<-[4..],y`mod`2>0]

, z `mod` 3 > 0 ])

= yields

prime

=

(25)

3

12

❚ prime can be used to check primality but be careful:

❚ Not to be in prime takes an infinite number of tests to check.

❚ Do we really have to test for all numbers in the list?

> elem prime 7 True

> elem prime 6

no reply!

13

elemOrd:: Ord a => [a] -> a -> Bool elemOrd (x:xs) y

| x < y = elemOrd xs y

| x == y = True

| otherwise = False

>elemOrd prime 6 False

No. Use the fact that the list is ordered:

14

Process Networks

❚ In Haskell not only lists but any data structure is implicitly infinite.

❚ But infinite lists are particularly interesting.

❚ They model data streams in networks where input and output are streams. Streams are manipulated by stream processing operations.

15

ai + bi

(0:) feedback

b1,b2,b3,…

a0,a1,a2,…

0,b1,b2,b3

A Sample Network

result input

16

network as = plus as (0:(network as)) where plus xs ys =

map (\(x,y)-> x+y) (zip xs ys)

>take 5 (network [1..]) [0,1,3,6,10]

This process network can be expressed using infinite lists and recursion. For example:

What does this compute?

bn =

a

0

+ a

1

+ a

2

+ … +

a n-1

17

Rabbit Reproduction

In an “ideal rabbit world” rabbits reproduce at the age of 2 months and from then on produce a new couple of rabbits every month.

If you start with one newborn couple, how many couples do you have after n months if no rabbits die (it’s an ideal world after all)?

(26)

4

18

How many rabbit couples are there ?

0 1 2 3 4

Months couples

+ + +

+

19

❚ Building principle:

❚ These numbers are called Fibonacci numbers.

❚ They occur often in nature (for example the number of florets in sunflowers etc. ).

❚ rabbits(n+1)/rabbits(n) converges to the golden ratio.

old rabbits new rabbits rabbits(n+2) = rabbits(n+1) + rabbits(n)

20

+

tail

feedback

1,1,b2,b3,b4,…

b2,b3,b4,…

Network for Fibonacci

(1:1:) 1,b2,b3,b4,…

output

21

fib = 1:1:(plus fib (tail fib)) where plus xs ys =

map (\(x,y) -> x+y)(zip xs ys)

> take 7 fib [1,1,2,3,5,8,13]

Implementation of the Fibonacci network using infinite lists:

22

Advantages of Infinite Lists

❚ Abstraction: programs can be designed without care about the possible length of the lists.

❚ Stream-based (process-based) programming of networks. Feedback by recursion.

❚ Making use of higher-order functions one can develop a library of network components that can be composed.

23

Exercises

Write a process network that merges two given input streams of numbers that are supposed to be ordered.

Write mergesort as a process network. Can it work for infinite lists?

Define a process network that computes the output stream of Hamming numbers in ascending order. The Hamming numbers are all the numbers which have prime factors in [2, 3, 5].

(1)

(2)

(3)

References

Related documents

compared the microbiota composition and diversity in upper and lower respiratory tract samples from 24 patients with interstitial lung disease or Pneumocystis

After the first stage of RNA-seq, the (mapped reads and) splice junctions identified by the aligner lay in local files which need to be merged into a single file.

We might say that the IPCC performed an important legitim- ating function for the speculative technology of BECCS, pulling it into the political world, making previously

The parent company's Retained Earnings will be increased by the cumulative total of the first three years of subsidiary profit, and the Subsidiary Income account will be increased

705 SANKHYA INFOTECH LIMITED, 1-1-39, Seven Hills Plaza,, Opp. 303, Turning Point Apts, Above, Syndicate Bank,Ameerpet, Hyderabad - 16.. 12, Banjara Hills, Hyderabad. LTD., 601,

Licensed indications &amp; key NICE guidance: Donepezil, galantamine and rivastigmine (AChE inhibitors) are licensed for the symptomatic treatment of mild to moderately

Of the 309 small businesses that received 424 Phase I awards, 76 companies (or 25%) that received DHS SBIR Phase I awards participated in the Federal SBIR program (i.e., across all

Such sites include the blog and discussion boards BiasedBBC.org (“Exposing the Broadcasting Bias”), dating back to at least 2003, and the StopTheBBC network of blog posts and