Download presentation

Presentation is loading. Please wait.

Published byBrodie Cauldwell Modified about 1 year ago

1
© M. Winter COSC 4P41 – Functional Programming Abstract data types (ADTs) An ADT is a data type together with some functions to manipulate elements of this data type. It usually consists of 1.a signature (interface), between the user and the implementor, 2.an implementation which is (completely) hidden to the user. Example: A calculator for numerical expressions. data Expr = Lit Int | IVar Var | Let Var Expr Expr | Expr :+: Expr | Expr :-: Expr | Expr :*: Expr | Expr :\: Expr

2
© M. Winter COSC 4P41 – Functional Programming ADTs (cont’d) eval :: Expr -> Store -> Int eval (Lit n) store = n eval (IVar v) store = value store v eval (Let v e1 e2) store = eval e2 (update store v (eval e1 store)) eval (e1 :+: e2) store = eval e1 store + eval e2 store eval (e1 :-: e2) store = eval e1 store - eval e2 store eval (e1 :*: e2) store = eval e1 store * eval e2 store eval (e1 :\: e2) store = eval e1 store `div` eval e2 store execute :: Expr -> Int execute e = eval e initial

3
© M. Winter COSC 4P41 – Functional Programming ADT Store The interface of Store consists of the functions / values 1.initial 2.value 3.update The implementation is hidden and can be exchanged. initial :: Store value :: Store -> Var -> Int update :: Store -> Var -> Int -> Store USER IMPLEMENTOR

4
© M. Winter COSC 4P41 – Functional Programming ADT Store (1 st implementation) module Store(Store,initial,value,update) where newtype Store = Sto [(Var,Int)] initial :: Store initial = Sto [] value :: Store -> Var -> Int value (Sto []) v = 0 value (Sto ((v',n):sto)) v | v == v' = n | otherwise = value (Sto sto) v update :: Store -> Var -> Int -> Store update (Sto sto) v n = Sto ((v,n):sto)

5
© M. Winter COSC 4P41 – Functional Programming ADT Store (2 nd implementation) module Store(Store,initial,value,update) where newtype Store = Sto (Var -> Int) initial :: Store initial = Sto (\v -> 0) value :: Store -> Var -> Int value (Sto sto) v = sto v update :: Store -> Var -> Int -> Store update (Sto sto) v n = Sto (\w -> if v==w then n else sto w)

6
© M. Winter COSC 4P41 – Functional Programming Type classes We can declare ADTs as belonging to particular type classes. instance Eq Store where (Sto sto1) == (Sto sto2) = sto1==sto2 instance Show Store where show (Sto sto) = show sto Note, that once declared, these instances cannot be hidden, so that even though they are not named in the export list, the functions over Store which are defined by means of these instance declarations will be available whenever the module Store is imported.

7
© M. Winter COSC 4P41 – Functional Programming ADT Queue The interface for the ADT Queue : type Queue a emptyQ :: Queue a isEmptyQ :: Queue a - > Bool addQ :: a -> Queue a -> Queue a remQ :: Queue a -> (a, Queue a) USER IMPLEMENTOR

8
© M. Winter COSC 4P41 – Functional Programming ADT Queue (1 st implementation) module Queue(Queue,emptyQ,isEmptyQ,addQ,remQ) where newtype Queue a = Qu [a] emptyQ :: Queue a emptyQ = Qu [] isEmptyQ :: Queue a -> Bool isEmptyQ (Qu xs) = null xs addQ :: a -> Queue a -> Queue a addQ x (Qu xs) = Qu (xs++[x]) remQ :: Queue a -> (a, Queue a) remQ xs) | not (isEmptyQ q)= (head xs, Qu (tail xs)) | otherwise= error ”remQ”

9
© M. Winter COSC 4P41 – Functional Programming Properties of the implementation One characteristic of this implementation is addQ is ‘expensive’, remQ is ‘cheap’. Alternative: addQ x (Qu xs) = Qu (x:xs) remQ xs) | not (isEmptyQ q)= (last xs, Qu (init xs)) | otherwise= error ”remQ” But now we have: addQ is ‘cheap’, remQ is ‘expensive’.

10
© M. Winter COSC 4P41 – Functional Programming ADT Queue (2 nd implementation) module Queue(Queue,emptyQ,isEmptyQ,addQ,remQ) where data Queue a = Qu [a] [a] emptyQ :: Queue a emptyQ = Qu [] [] isEmptyQ :: Queue a -> Bool isEmptyQ (Qu [] []) = True isEmptyQ _ = False addQ :: a -> Queue a -> Queue a addQ x (Qu xs ys) = Qu xs (x:ys) remQ :: Queue a -> (a, Queue a) remQ (Qu (x:xs) ys)= (x, Qu xs ys) remQ (Qu [] (y:ys))= remQ (Qu (reverse (y:ys)) []) remQ (Qu [] [])= error ”remQ”

11
© M. Winter COSC 4P41 – Functional Programming Why is there no lengthQ function? Consider the following implementation of the function lengthQ computing the length of a queue: lengthQ :: Queue a -> Int lengthQ q | isEmpty q= 0 | otherwise= 1 + (lengthQ. snd. remQ) q The definition of lengthQ is independent of the implementation, and so would not have to be reimplemented if the implementation of the type Queue a is changed. This is a good reason for leaving lengthQ out of the signature.

12
© M. Winter COSC 4P41 – Functional Programming Further examples of ADTs the type Tree a of binary trees whose elements are of type a, binary search trees as an extension of binary trees whose elements are ordered, the type of sets, the type of relations between a and b, the type of a graph with node from a (special case of a relation).

13
© M. Winter COSC 4P41 – Functional Programming Parsing Consider again the following data type for expressions: data Expr = Lit Int | IVar Var | Let Var Expr Expr | Expr :+: Expr | Expr :-: Expr | Expr :*: Expr | Expr :\: Expr The class Read can be used to generate elements of type Expr given a string representation. Notice, that the derived read function would accept strings as ”Lit 4 :\: Lit 2” rather than the natural representation ”4 \ 2”.

14
© M. Winter COSC 4P41 – Functional Programming A type for parsers First attempt: type Parse1 a b = [a] -> b Suppose that bracket and number are parsers of this type which recognize brackets and numbers: bracket ”(xyz” ‘(‘ number ”234” 2 or 23 or 234 bracket ”234” no result? Second attempt: type Parse2 a b = [a] -> [b] bracket ”(xyz” [‘(‘] number ”234” [2,23,234] bracket ”234” []

15
© M. Winter COSC 4P41 – Functional Programming A type for parsers (cont’d) Final attempt: type Parse a b = [a] -> [(b,[a])] bracket ”(xyz” [(‘(‘,”xyz”)] number ”234” [(2,”34”),(23,”4”),(234,””)] bracket ”234” []

16
© M. Winter COSC 4P41 – Functional Programming Some basic parsers none :: Parse a b none inp = [] succeed :: b -> Parse a b succeed val inp = [(val,inp)] token :: Eq a => a -> Parse a a token t (x:xs) | t==x = [(t,xs)] | otherwise = [] token t [] = [] spot :: (a -> Bool) -> Parse a a spot p (x:xs) | p x = [(x,xs)] | otherwise = [] spot p [] = []

17
© M. Winter COSC 4P41 – Functional Programming Some basic parsers (cont’d) Some examples: bracket :: Parse Char Char bracket = token ‘(‘ bracket ”(xyz” [(‘(‘,”xyz”)] dig :: Parse Char Char dig = spot isDigit dig ”23df” [(‘2‘,”3df”)]

18
© M. Winter COSC 4P41 – Functional Programming Combining Parsers alt p1 p2 recognizes anything recognized by p1 or by p2. alt :: Parse a b -> Parse a b -> Parse a b alt p1 p2 inp = p1 inp ++ p2 inp (bracket `alt` dig) ”234” Apply one parser then the second to the result(s) of the first. infixr 5 >*> (>*>) :: Parse a b -> Parse a c -> Parse a (b,c) (>*>) p1 p2 inp = [((y,z),rem2) | (y,rem1) <- p1 inp, (z,rem2) <- p2 rem1 ] (bracket >*> dig) ”(234” [((‘(‘,‘2‘),”34”)]

19
© M. Winter COSC 4P41 – Functional Programming Combining Parsers (cont’d) Transform the results of the parses according to the function. build :: Parse a b -> (b -> c) -> Parse a c build p f inp = [ (f x,rem) | (x,rem) <- p inp ] (dig `build` char2int) ”23df” [(2,”3df”)] infixr 5.*> (.*>) :: Parse a b -> Parse a c -> Parse a c p1.*> p2 = (p1 >*> p2) `build` snd infixr 5 >*. (>*.) :: Parse a b -> Parse a c -> Parse a b p1 >*. p2 = (p1 >*> p2) `build` fst

20
© M. Winter COSC 4P41 – Functional Programming Combining Parsers (cont’d) Recognize a list of objects. list :: Parse a b -> Parse a [b] list p = (succeed []) `alt` ((p >*> list p) `build` convert) where convert = uncurry (:) list dig ”234(” [(””,”234(”),(”2”,”34(”),(”23”,”4(”),(”234”,”(”)] stringToken :: String -> Parse Char String stringToken s1 s2 = [ (a,b) | (a,b) <- lex s2, a==s1]

21
© M. Winter COSC 4P41 – Functional Programming Parsing expressions Grammar for expressions: Expr = Int | Char | let Char = Expr in Expr | (Expr + Expr) | (Expr - Expr) | (Expr * Expr) | (Expr div Expr) Example: (4 + 3) div 2

22
© M. Winter COSC 4P41 – Functional Programming Parsing expressions parseVar = spot (\x -> 'a' <= x && x <= 'z') parser = (reads `build` Lit) `alt`(parseVar `build` IVar) `alt`((stringToken "let".*> parseVar >*> stringToken "=".*> parser >*> stringToken "in".*> parser) `build` (\(v,(e1,e2)) -> Let v e1 e2)) `alt`((stringToken "(".*> parser >*> stringToken "+".*> parser >*. stringToken ")") `build` (uncurry (:+:))) `alt`((stringToken "(".*> parser >*> stringToken "-".*> parser >*. stringToken ")") `build` (uncurry (:-:))) `alt`((stringToken "(".*> parser >*> stringToken "*".*> parser >*. stringToken ")") `build` (uncurry (:*:))) `alt`((stringToken "(".*> parser >*> stringToken "div".*> parser >*. stringToken ")") `build` (uncurry (:\:)))

23
© M. Winter COSC 4P41 – Functional Programming Parsing expression (cont’d) parse str = if null p then error ”Parse error: no parse” else if snd e /= ”” then error ”Parse error: unexpected end of input” else fst e where p = parser str e = head p instance Read Expr where readsPrec n = parser

24
© M. Winter COSC 4P41 – Functional Programming Further considerations Alternative grammar for expressions: Expr = Int | Char | let Char = Expr in Expr | (Expr) | Expr + Expr | Expr - Expr | Expr * Expr | Expr div Expr A similar translation into a Haskell program does not work !!! Reason: the grammar above is left-recursive.

25
© M. Winter COSC 4P41 – Functional Programming Further considerations (cont’d) Solution: Modify grammar as follows: Expr = Expr1 | Expr1 + Expr | Expr1 - Expr | Expr1 * Expr | Expr1 div Expr Expr1 = Int | Char | let Char = Expr in Expr | (Expr)

26
© M. Winter COSC 4P41 – Functional Programming Using Parsec parser = do { n <- read2Parsec; -- function in Basics.hs return $ Lit n } … do { strings “(”;-- function in Bascics.hs -- Parsec only defines -- string :: String ->... t1 <- parser; spaces; strings “-”; t2 <- parser; spaces; strings “)”; return $ t1 :-: t2 }

Similar presentations

© 2017 SlidePlayer.com Inc.

All rights reserved.

Ads by Google