CS345H: Programming Languages Lecture 19: Haskell Overview
Total Page:16
File Type:pdf, Size:1020Kb
Overview CS345H: Programming Languages I Today: Look at the Haskell programming language I Like LISP, Haskell is a functional language Lecture 19: Haskell I Unlike LISP, Haskell is statically typed and has an expressive type system Thomas Dillig I Integrates many concepts we looked at: static typing, type inference, polymorphism, higher-order functions, . I At the cutting edge of PL research: designed by researchers, lots of new research done in the context of Haskell Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 1/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 2/33 Little Bit of History History of Haskell I Designed in the early 90’s by a committee of researchers I Haskell borrows ideas from both LISP and ML I Goal was to unify research efforts in pure, lazy functional languages I Like LISP and ML, functional language I Feeling was that widespread use of lazy functional languages was being hampered by lack of standard language I Like ML, has a strong, expressive static type I Goal of the committee was to design a lazy functional system language that would become standard I But also different from I People who played key role in designing Haskell: Simon both in some ways: e.g., Peyton Jones (Microsoft Research), Philip Wadler lazy functional language (Edinburgh), Paul Hudak (Yale), John Hughes (Chalmers) Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 3/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 4/33 Why Called Haskell? Overview of Haskell Features I The Haskell programming language is named after logician Haskell B. Curry I Lazy evaluation I Haskell curry well-known for Curry-Howard isopmorphism I Expressive static type system I Curry-Howard isomorphism sheds light on relationship between I Polymorphism and type classes constructive logic and functional programming languages I Tagged unions, type constructors I Specifically, it says: I Pattern matching 1. Propositions are types I List comprehension 2. Proofs are programs 3. Proof checking is type checking Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 5/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 6/33 1 Lazy vs. Strict Programming Languages Example of Lazy vs. Eager I Haskell is different from many other functional languages in that it’s lazy I Suppose you pass a divergent (i.e., non-terminating) expression as an argument to a function I Lazy (or call-by-need, non-strict) languages delay evaluation of an expression until its value is actually required I In an eager language, the program will definitely not terminate I In contrast, eager (or strict, call-by-value) languages, an I In a lazy language, the program will terminate if the value of expression is evaluated as soon as it is bound to a variable, that argument is not needed in the called function regardless of whether the variable is used or not I There are both advantages and disadvantages of lazy I The default behavior in many languages used today is eager evaluation evaluation: Java, C, C++, ML, Python, Lisp, Scheme . Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 7/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 8/33 Advantages and Disadvantages of Lazy Evaluation Expressive Static Type System Advantages of Lazy Evaluation: I Haskell is a statically typed language with a sound type system I Unused arguments are not evaluated – can be a big win if evaluation of expression is expensive I Does not allow ways to subvert the type system, such as casting I Can avoid divergent or buggy bahevior in some cases I Thus, if the Haskell compiler assigns type T to expression e, I Can create infinite data structures run-time value of e will be in the set of values defined by T Disadvantages of Lazy Evaluation: I Can be difficult to predict program behavior I Haskell performs type inference, so you don’t have to explicitly annotate types of expressions I Doesn’t work well in the presence of side effects I Furthermore, Haskell has polymorphism: Types of variables I Even in purely functional languages, things like IO become can contain (universally-quantified) type variables much more difficult Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 9/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 10/33 Example of Polymorphism in Haskell Another Example I Let’s look at a more interesting example: map f [] = [] I Consider the id function in Haskell: let id x = x map f (x:xs) = f x : map f xs I This function has the inferred polymorphic type a -> a I Here, we define a higher-order map function which applies a function f to every element in the list I For any type a, if the value of the input is a, the output is also of type a I This function definition illustrates pattern matching in Haskell: here, we pattern match on the second argument I The Haskell type a -> a is the same as α.α α ∀ → I First line: if the input list is empty, then return the empty list I Second line corresponds to case where list has at least one element Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 11/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 12/33 2 Example, cont. Example, cont. map f [] = [] map f [] = [] map f (x:xs) = f x : map f xs map f (x:xs) = f x : map f xs I By using the notation (x:xs), we bind first element of input I Haskell compiler infers type of this function to be: list to x and rest of the list to xs (a -> b) -> [a] -> [b] I Second line: Applies function f to head x of the list I Again, this is a polymorphic type I Then, recursively invokes map with function f on the I Says: Given any function of type a -> b and a list of values remainder xs of the list of type a, return value is a list of values of type b I Finally, returns a list which is the concatanation of f x and I Here, a and b are (implicitly) universally-quantified type result of recursive call variables Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 13/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 14/33 Type Classes Type Class Example I Consider the Haskell function: f x = x*2 I The type of the function f x = x*2 in Haskell is actually: I What is the type of this function? (Num a) => a -> a I We can’t give it the polymorphic type a -> a because it only I Says: For any type a that belongs to type class Num, function works on types for which multiplication is defined f takes a value of type a and return a value of type a I But assigning type Integer -> Integer also too restrictive I Since integers, floats etc. all belong to the Num type class, this because works for floats or other types for which * is defined type is very general! I Haskell solves this problem through type classes Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 15/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 16/33 Programming with Type Classes Programming with Type Classes, cont. I To use this feature of Haskell, first need to declare type classes I Then, we declare instances of a type class I A type class is simply a set of types that support a common set of operations I Example: instance Num Int where I To define the type class, declare the common operations and a+b = intPlus a b give type class a name a*b = intTimes a b ... I Example: I Instance declarations show how Num operations are class Num a where implemented for a particular type (+) :: a-> a -> a (*) :: a -> a -> a ... I Using type class and instance declarations, Haskell can infer general and useful types such as: I This declares a type class called Num that supports operations (Num a) => a -> a + and * Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 17/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 18/33 3 Algebraic Data Types Tagged Union Example data Student = BS (Name, Dept) | MS (Name, Dept, Area) I Another useful feature of Haskell is algebraic data types, also I Here, BS and MS are constructors called tagged unions or discriminated unions I The BS constructor must be applied to a pair consisting of a I Suppose we want to have a type to represent students name and department I For undergraduates, we want to track their name and I The MS constructor must be applied to tuple consisting of department name, department, and specialty I For masters students, we want to track their name, I Thus, Student is really a union of the two types Name*Dept department, and specialty and Name*Dept*Area I In Haskell, you can have a data type to represent both I Here, A*B is a product type which corresponds to type of undergraduate and masters students: tuple whose elements are of type A and B Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 19/33 Thomas Dillig, CS345H: Programming Languages Lecture 19: Haskell 20/33 Pattern Matching on Data Types Recursive Data Types I Now, suppose we want to write a name function that gives the name of any student I Data types in Haskell can also be recursive I We can conveniently do this in Haskell through I i.e., data type being declared can apprear as arguments of pattern-matching: type constructors name (BS(n,d)) = n I Example: name (MS(n,d, a)) = n data Tree = Leaf Int | Node (Tree, Tree) I Haskell compiler will infer type of name as Student -> Name I Here is how you would write a function in Haskell that checks I This is another example of pattern matching in Haskell if a given integer is in the tree: inTree x (Leaf y) = x==y I First line matches on students with type constructor BS