1 / 17

Functional Programming Lecture 10 - type checking

Functional Programming Lecture 10 - type checking. Strong Typing. Haskell is a strongly typed programming language. This means that every value has a defined type, and we can check that type before evaluating the value. Benefits - many errors are caught before run-time

varana
Download Presentation

Functional Programming Lecture 10 - type checking

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Functional ProgrammingLecture 10 - type checking

  2. Strong Typing Haskell is a strongly typed programming language. This means that every value has a defined type, and we can check that type before evaluating the value. Benefits - many errors are caught before run-time - use types to categorise and lookup functions A type may be monomorphic, polymorphic, or an instance of a type class. Note: we can always make a monomorphic instance of a polymorphic type. E.g. length :: [a] -> Int (polymorphic) lengthInt :: [Int] -> Int (monomorphic)

  3. Monomorphic Type Checking Expression:a literal, a variable, a constant, a list, a tuple, or a function application. Inference rules for type checking a list: x:: t xs :: [t]_________ x:xs :: [t] [] :: [t] In words, If x has type t and xs is a list of t x:xs then result has type list of t Examples: Show [True, False] :: [Bool] Show [3,True] is not well-typed.

  4. Inference rule for type checking a tuple: x1 :: t1 xn :: tn (x1, …., xn) :: (t1, …., tn) In words, if each component xi has typeti (x1, …., xn) then result has type tuple (t1, …., tn) Examples: Show (True,3) :: (Bool,Int)

  5. Inference rule for type checking a function application: f :: s -> t e :: s f e :: t In words, f has type s -> t e has type s f e result has type t Examples: Show 2 + Int 3 :: Int Show (ord ‘c’) + Int 3 :: Int Show (ord ‘c’) + Int True is not well-typed.

  6. Type Checking Function Definitions To check a function f :: t1 -> t2 -> … -> tk -> t when there are several cases, i.e. f p1 p2 … pk | g1 = e1 | g2 = e2 … | gl = el We need to check that - each of the guards gi is of type Bool - the value of each ei is of type t - each pattern pj matches some element of type tj. E.g. pattern p:q matches an element of type [t] when p matches an element of t and q matches an element of [t].

  7. Type Checking Function Definitions Example f :: Int -> [Int] -> Int f a (x:xs) | (a>x) = a + x | (a ==x) = x Note: | (x >xs) = a type error Can we deduce type of f? Let (x:xs):: [b], then x::b. a has same type as x, so a::b. b must be numeric, assume b=Int. f:: t1 -> t2 -> t3 p1=a, so p1matches an element of Int p2=x:xs so p2matches an element of [b] = [Int] e1=a + x, a has type Int So f :: Int -> [Int] -> Int

  8. Polymorphic Type Checking Type checking a polymorphic type is the same as solving type constraints. Some examples: Consider f (x,y) = (x,[‘a’ .. y]) a pair a character - the argument to f is a pair - x is completely unconstrained - y is an expression in an enumerated type, starting with a Char, so y must have type Char - [‘a’ .. y] has type [Char] - the rhs is a pair. Therefore, f :: (a,Char) -> (a, [Char])

  9. Consider g (m,zs) = m + length zs a pair adds values [b] -> Int - m must have a numeric type - zs must be a list type, call it [b] - length zs :: Int, so this forces m to have type Int - since m has type Int, the rhs must have type Int - we don’t know anything else about zs. Therefore, g :: (Int,[b]) -> Int.

  10. Function Composition Two functions can be composed in Haskell, just as in Maths. Consider composition of f1 and f2. f2.f1 a a f1 b f2 c c f1 a = b, f2 b = c. f2.f1 takes in a and outputs c. Definition (f2 . f 1) x = f2 (f1 x) -- the output of f1 becomes the input of f2 The type of _._ is _._ :: (b -> c) -> (a -> b) -> (a -> c) type of f2 type of f1 type of f2.f1 -

  11. Function Composition h = f2 . f1 (b -> c) (a -> b) the input the output result is function from input to output h :: a -> c

  12. Now consider the type of h = g . f g :: (Int,[d]) -> Int -- rename type var b as d g (m,zs) = m + length zs f :: (e,Char) -> (e, [Char]) -- rename type var a as e f (x,y) = (x,[‘a’ .. y]) The type of _._ is _._ :: (b -> c) -> (a -> b) -> (a -> c) g f Therefore the type of g . f is b=(Int, [d]) a=(e,Char) c=Int b=(e,[Char]) We have to “unify” the two definitions of b: (Int,[d]) = (e,[Char]) Solution: e=Int, d=Char Therefore, h :: a -> c h :: (Int,Char) -> Int -

  13. Unification Unification is the process of matching two terms, that is making substitutions to each term. How do you describe the “unification” of (e,[Char]) and (Int,[d])? (Bool, [Char]) (Int,[Int]) (Char,[Char]) (Int, [Char]) (Int,[Bool]) (a->a, [Char]) (Int, [[c]]) … … (e, [Char]) (Int,[d]) The unification of two expressions is the intersection of the sets of types of those two expressions. This intersection is given by most general common instance of the two expressions. The unifier is the subsitution: e = Int, d = Char.

  14. Unification Not all expressions can be unified. For example, consider [Int] -> [Int] and a -> [a]. These constraints are inconsistent, the two expressions cannot be unified. [Int] -> [Int] no solution a -> [a] a=Int,a=[Int]

  15. Type checking polymorphic function application Assume f :: s -> t e :: u f e has type has type s -> t u unify s and u by s’ s’ -> t’ s’

  16. Type checking polymorphic function application Example: map :: (a -> b) -> [a] -> [b] ord :: Char -> Int What is type of map ord? Must unify a->b and Char -> Int. So, a=Char, b=Int. map ord :: [a] -> [b] map ord (a ->b) -> [a]->[b] Char -> Int s -> t u (Char -> Int) ->[Char] ->[Int] s’ -> t’ Therefore map ord :: [a] -> [b] map ord :: [Char]-> [Int] Note: the result type may still contain type variables.

  17. Resolving Type Ambiguity A final note on types. Assume you have defined: f :: Show a => [a] -> String -- f converts lists of a to string format, e.g. sets f [] = “{}” f (x:xs) = “{“ ++ ( g (x:xs)) ++ “}” where g [x] = show a g x:y:xs = (show a) ++ “,” ++ …. Then f [] will be ambiguous, that is, it won’t know which type a to check as a Show type! > f [] • ERROR: Unresolved overloading • *** type : Show a => [Char] • *** expression : print1 [] Solution: > f ([]::String)“{}” NB. You could force [] to have any list of Show type.

More Related