1 / 31

310 likes | 380 Vues

(1). What are the types of the following values?. Exercises. [’a’,’b’,’c’] (’a’,’b’,’c’) [(False,’0’),(True,’1’)] ([False,True],[’0’,’1’]) [tail,init,reverse]. (2). (3). What are the types of the following functions?. Check your answers using Hugs. second xs = head (tail xs)

Télécharger la présentation
## Exercises

**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

**(1)**What are the types of the following values? Exercises [’a’,’b’,’c’] (’a’,’b’,’c’) [(False,’0’),(True,’1’)] ([False,True],[’0’,’1’]) [tail,init,reverse] K. Louden, Programming Languages**(2)**(3) What are the types of the following functions? Check your answers using Hugs. second xs = head (tail xs) swap (x,y) = (y,x) pair x y = (x,y) double x = x*2 palindrome xs = reverse xs == xs twice f x = f (f x) K. Louden, Programming Languages**Curried Functions**mult:: Int -> Int -> Int mult x y = x * y • We could read this as a function taking two Int arguments and returning a third. OR-- a function taking a single Int argument and returning a function from Int -> Int as a result. • Moral: the mult function can take either one or two parameters; if you give it one, it returns a function of the (missing) 2nd parameter • Ex: map (mult 3) [1,2,3] Yields [3,6,9] K. Louden, Programming Languages**Curried Functions**• Contrast the previous definition of mult with a definition using a tuple: mult2 :: (Int,Int) -> Int mult2 (x,y) = x *y • Now we must always supply both parameters at every call:The mult function is Curried (named after Haskell B. Curry), the mult2 function is not. K. Louden, Programming Languages**Curried Functions**• Definition: A function taking multiple parameters is Curried if it can be viewed as a (higher-order) function of a single parameter. • Currying is good, since all functions can be viewed as having just a single parameter, and higher-order functions can be obtained automatically. K. Louden, Programming Languages**Haskell**• A fully-Curried lazy purely functional language with Hindley-Milner static typing. (Fully-Curried means all functions, including built-in arithmetic, are implicitly Curried.) • Has many other features that make it perhaps the most advanced functional language available today. • Includes overloading and a built-in mechanism for generator-filter programming (called list comprehensions). K. Louden, Programming Languages**Sample Haskell code:**fact n = if n == 0 then 1 else n * fact (n-1) square x = x * x pi1 = 3.14159 gcd1 u v = if v == 0 then u else gcd1 v (mod u v) squarelist lis =if (null lis) then liselse square (head lis): squarelist (tail lis) K. Louden, Programming Languages**Haskell properties**• Parentheses are only necessary for grouping. • Semicolons are usually unnecessary. • Definitions have no special syntax, so they must be loaded from a file—they cannot be entered directly into an interpreter. • Operators are infix. • Lists are written using square brackets and commas (e.g. [1,2,3]), with ++ as the list append operation, and : (colon) as the list constructor operation. • All value and function names must start with a lowercase letter, and all types are uppercase: Int. • Names cannot be redefined unless you state you are overriding them - hence the use of pi1 & gcd1 in the previous slide (pi & gcd are predefined). K. Louden, Programming Languages**Haskell properties (2)**• Haskell is purely functional, so there are no variables or assignments, and I/O and sequencing cannot be done except using special tools, called monads (which we do not study here). • Of course, there are still local definitions (in other words no value is being stored, we are just defining the pattern):let x = 2; y = 3 in x + yor: let x = 2 y = 3 in x + y • Note indentation in the previous code to get rid of the semicolon: Haskell uses a two-dimensional Layout Rule to remove extra syntax. Leading white space matters! K. Louden, Programming Languages**Haskell properties (3)**Note lambda syntax • All local definitions are recursive:f x = let z = x-1 g = \y->if y==0 then z else g(y-1) in g x + 2 • All expressions are delayed in Haskell: ones = 1:ones -- can also write [1,1..] ints_from n = n : ints_from (n+1) ints = ints_from 1 -- also: [1..] • Infix operators can be made prefix by putting parentheses around them:doubleIt lis = map ((*) 2) lis Comment K. Louden, Programming Languages**Haskell properties (4)**• Hindley-Milner type checking is performed on all definitions and expressions. Type variables use the names a, b, c, etc. • Types are not automatically displayed, but can be viewed by using the :t command in the interpreter. Small sample interpreter session:> [1]++[2][1,2]> :t (++)(++) :: [a] -> [a] -> [a]> [1]++['a'] – wants types to match error:No instance for (Num Char) arising from the literal `1' at <interactive>:1:1 Probable fix: add an instance declaration for (Num Char) In the list element: 1 In the first argument of `(++)', namely `[1]' In the definition of `it': it = [1] ++ ['a'] K. Louden, Programming Languages**Strong typing**• Checks whether or not expressions we wish to evaluate or definitions we wish to use obey typing rules without any evaluation taking place. • A pattern is consistent with a type if it will match some elements of that type. • A variable is consistent with any type • A pattern (t:ts) is consistent with [p] if t is consistent with p and ts is consistent with [p] K. Louden, Programming Languages**Type Checking**f:: a->b->c f x y | g1 = e1 | g2 = e2 |otherwise = e3 We must check • g1 and g2 are boolean • x is consistent with a and y is consistent with b • e1,e2,e3 are all of type c. K. Louden, Programming Languages**Examples of type inference**• f (x,y) = (x,[‘a’..y]) • What is the type of f? • The argument of f is a pair. We consider separately the constraints of x and y. Y is used with [‘a’..y] so it must be a Char. • f :: (a, Char) -> (a, [Char]) K. Louden, Programming Languages**Examples of type inference**• g(m,z) = m + length z • What constraints are placed on m and z? M must be numeric, as used with +. z must be a list as used with length. Furthermore, since length returns an int, we assume m is also an Int. • Now consider the function composition • The input of g must be the output of f • g . f :: (Int, Char) -> Int • *Main> K. Louden, Programming Languages**Unification**• We describe the intersection of the sets given by two type expressions. • The unification of the two is the most general common instance of the two type expressions. K. Louden, Programming Languages**Unification need not result in a monotype.**• (a,[a]) and ([b],c) unify as • ([b], [[b]]) K. Louden, Programming Languages**Patterns in Haskell**• Patterns can be used in function definitions • Typical patterns are 0 for zero, [] for the empty list, and (x:xs) for a nonempty list. • fact and squarelist :fact 0 = 1fact n = n * fact (n-1)squarelist [] = []squarelist (x:xs) = (square x) : squarelist xs • Of course, it would be better to use map:squarelist lis = map square lis K. Louden, Programming Languages**Patterns in Haskell (cont.)**• Because of patterns, it is unusual in Haskell to use head, tail, and null. • The anonymous wildcard pattern (matches anything) is the underscore in Haskell. • Overlapping patterns are ok (see fact on previous slide). Non-exhaustive patterns can also be used, and do not generate a warning • Patterns are syntactic sugar for case expressions:fact n = case n of 0 -> 1 _ -> n * fact (n-1) K. Louden, Programming Languages**Haskell List Comprehensions**• Generators and filters can be expressed together in Haskell in a quasi-list notation called a list comprehension: odds = [n | n <- [1..], mod n 2 /= 0]-- can also write [1,3..] • Multiple generators and filters can be combined in a single list comprehension:mystery = [n+m|n <-[1..], m <-[1..], mod n m /= 0] • List comprehensions allow many snappy programs to be written: (mod without quotes is prefix)sieve (h:t) = h:sieve [n|n <- t, mod n h /= 0]primes = sieve [2..] K. Louden, Programming Languages**Haskell Data Structures**• So far we have only seen lists in Haskell, although we know that static typing does not allow lists to imitate structs or classes as in Scheme. • Haskell has built-in tuple types. which are Cartesian products (like structs but with no field names):intWithRoot:: Int -> (Int,Double)intWithRoot x = (x , sqrt (fromInt x)) • Use patterns to get the components out:rootOf x = let (_,r)=intWithRoot x in r • Tuple types are written the same way values are, K. Louden, Programming Languages**Haskell Data Structures (2)**• Lists and tuples do not go far enough, since unions cannot be expressed. • User-defined types can be introduced using data definitions:data Direction = North|East|South|West • Haskell can have polymorphic types and constructors with more than one parameter data Either1 a b = Left1 a | Right1 b fun ::Either1 a b -> Bool fun (Left1 _) = True fun (Right1 _) = False fun (Left1 5) True :t Left1 "hi" Left1 "hi" :: Either1 [Char] b K. Louden, Programming Languages**Haskell Data Structures (3)**• Note how the previous definition expresses a tagged union of two polymorphic types. • Binary search tree example (recursive type):data BST a = Nil | Node a (BST a) (BST a)simpleBST = Node "horse" Nil Nil -- value • Constructors can be used as patterns:tree_to_list Nil = []tree_to_list (Node val left right) = (tree_to_list left) ++ [val] ++ (tree_to_list right) • Type synonyms can also be defined:type IntDouble = (Int,Double) • Note: all type and constructor names must be uppercase. K. Louden, Programming Languages**member a -> [a] ->Bool**Can check for equality, but this only works when a is a type for which equality is defined. How do we express that? We call the collection of types over which a function is defined to be the type class. For instance, the set of types over which == is defined is the equality class. K. Louden, Programming Languages**How do we define such a class**• We say what is needed for a type a to be in a class. In this case, we need == defined over a. In other words, a ->a->Bool class Eq a where (==) :: a-> a-> Bool Members of a type class are called its instances. Functions from Int->Int are NOT of type Eq since there is no algorithm to decide if two functions have the same behavior K. Louden, Programming Languages**Overloading in Haskell**• Many functions in Haskell are overloaded, in that they can take values from a (finite) number of different types. An easy example is the square function, defined by square x = x * x. • The type of square in Haskell is:square :: Num a => a -> a • This says basically that square is defined for any Num a type (such types all have a * function). • The type Num a => a is called a qualified type, and Num is called a type class. • Type classes are a bit like Java interfaces: they require that a certain function be defined, and each associated type must then implement it. K. Louden, Programming Languages**Overloading in Haskell (2)**• Here is an example of how to define a Sizeable type class that provides a measure of the size of a piece of data:class Sizeable a where size:: a -> Int • Now any type that you want to implement Sizeable must be declared an instance of the Sizeable class: (i.e., belongs to that class):instance Sizeable [a] where size = length instance Sizeable (BST a) where size Nil = 0 size (Node d l r) = (size l)+(size r) + 1 K. Louden, Programming Languages**Overloading in Haskell (3)**• Now any use of the size function automatically adds the Sizeable qualification to a type:trivial x = size x == 0 This function has type:Sizeable a => a -> Bool • Type classes usually require multiple functions:class Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a abs :: a -> a ...etc. instance Num Int where (+) = primPlusInt (-) = primMinusInt negate = primNegInt ...etc. Built-in "hidden" definitions K. Louden, Programming Languages**Overloading in Haskell (4)**• Type classes may need to "inherit" functions from other type classes (similar to interface inheritance in Java):class Eq a where (==), (/=) :: a -> a -> Bool x == y = not (x/=y) x /= y = not (x==y) class (Eq a) => Ord a where (<),(<=),(>=),(>) :: a -> a -> Bool max, min :: a -> a -> a instance Eq Int where … instance Ord Int where ... Note default definitions K. Louden, Programming Languages**Numeric Type Class Hierarchy**is read “is an instance of” K. Louden, Programming Languages**Overloading in Haskell (5)**• The Show class allows a data type to be displayed as a String (e.g. by the interpreter):class Show a where show :: a -> String • So many data types need to be made instances of Show and Eq that Haskell can do it automatically:data BST a = Nil | Node a (BST a) (BST a) deriving (Show,Eq) • Overloading presents challenges for Hindley-Milner type checking that result in some surprises: squarelist = map square gives squarelist the type [Integer] -> [Integer] (no overloading!) K. Louden, Programming Languages

More Related