COP 4020 Lecture -*- Outline -*- * The Haskell Language (4.7) (skip) successful, practical, completely declarative language ** features ------------------------------------------ HASKELL (See haskell.org) nonstrict strongly typed functional implicit currying monads Example: > t :: Integer -> Integer > t n = if odd n then (3*n+1) `div` 2 > else n `div` 2 > hailstones :: Integer -> [Integer] > hailstones n = n : hailstones (t n) ------------------------------------------ nonstrict means it's lazy monads can be used to replace state Explain the example's notation Also note that indentation is significant! Try: take 20 (hailstones 27) ** computation model (4.7.1) ------------------------------------------ COMPUTATION MODEL (4.7.1) Don't evaluate expression unless Consider an expression as a tree. When needed, Haskell - evaluates leftmost subexpression if it's a constructor, then done if it's a function, and no args, then done if it's a function with args, then apply to first argument by substituting argument in body then reevaluate Needs: - built-in functions (+, -, *) - pattern matching ------------------------------------------ ... it is definitely needed acts like normal order evaluation, only does as much as necessary ** Lazy evaluation (4.7.2) ------------------------------------------ LAZY EVALUATION (4.7.2) Laziness: functions evaluate expressions at most once Example: > h27 = hailstones 27 ------------------------------------------ This causes no problem, even though it's infinite, unless we try to print it... try: take 5 h27 ** Currying (4.7.3) ------------------------------------------ IMPLICIT CURRYING (4.7.3) Functions are implictly curried > add x y = x + y > add3 = add 3 > result = add3 7 > doubleList = map (2*) ------------------------------------------ The notation (2*) is a section, shorthand for (\ x -> 2*x) which is like fun {$ X} 2 * X end in Oz ** polymorphic types (4.7.4) ------------------------------------------ TYPE NOTATION Type operators operator meaning ============================= _ -> _ function type (_ , _) product type [ _ ] list type Associativity b f g x means (((b f) g) x) a -> b -> c means a -> (b -> c) ------------------------------------------ Q: Why do you think the associativity is different for applications and for function types? ** polymorphic types (Thompson 9.2, Davie 4.2) ------------------------------------------ POLYMORPHIC TYPES Monomorphic examples: Integer [Bool] -> Bool [(Integer, Integer) -> Bool] Polymorphic examples: [a] [b] -> b [(c,c) -> Bool] ------------------------------------------ Q: What are some expressions that have these types? Explain in terms of universal quantifiers. Q: What are some other instances of these types? ------------------------------------------ ALGEBRAIC TYPES Can simulate enumerations > data Font = Roman | Italic | Bold data Color = data Boolean = Can also be used to define recursive types, including data HaskellType = ------------------------------------------ ... Red | Blue | Yellow ... True | False Note that the constructor names must start with upper case letter! ... including grammars ... Unit | BuiltIn String | Synonym String | List HaskellType | HaskellType `Arrow` HaskellType | Tuple [HaskellType] | Data String ------------------------------------------ OVERVIEW OF TYPE INFERENCE Type checking: you declare type, compiler infers type, compiler compares Type inference: compiler infers type In Haskell don't need to declare types (usually) Example > mymap f [] = [] > mymap f (x:xs) = (f x):(mymap f xs) ------------------------------------------ do the inference (quickly, we'll see more later) mymap :: a = (b -> c) f :: b etc. since the variables are unconstrained, this is polymorphic ** Type classes (Thompson 12, Davie 4.8) (CTM 4.7.5) See paper by Wadler and Blott (POPL 89) ------------------------------------------ AD HOC POLYMORPHISM parametric polymorphism: map :: (a -> b) -> [a] -> [b] ad hoc polymorphism > square :: Num a => a -> a > square x = x * x ------------------------------------------ the point is that square x only works on those x for which * is defined it's illuminating to make a parametric version of this: squareP :: (a -> a -> a) -> a -> a squareP mult x = x `mult` x So what square needs to be polymorphic, is an additional "capability", the appropriate multiplication routine. Q: Why not require that you actually pass the multiplication yourself? Q: What's done in OO programming? lookup the method, based on the run-time type this isn't the run-time type, but the static type (note that there's no subtyping in Haskell, we know exact type of everything) But the idea is similar, we group types with related sets of operations into type classes, the type context (Num a =>) gives the name of the type class required *** type classes (Thompson 12.4) ------------------------------------------ TYPE CLASSES IN HASKELL -- abbreviated Eq type class class Eq a where (==), (/=) :: a -> a -> Bool x /= y = not (x==y) -- abbreviated Ord type class class (Eq a) => Ord a where compare :: a -> a -> Ordering (<), (<=), (>=), (>) :: a -> a -> Bool max, min :: a -> a -> a ------------------------------------------ there is a "default method" provided for /=, and the ordering stuff This is just like an "abstract class" in OOP, but remember it's *static* overloading data Ordering = LT | EQ | GT deriving (Eq, Ord, Ix, Enum, Read, Show, Bounded) The Ord type class is a *subclass* of Eq, it inherits defs from Eq, really if you think of these as requirements, it's a refinement (stronger requirement) on clients. There are also various ways to declare that a type you make up is an instance of a type class. *** type class instances (Thompson 12.3) ------------------------------------------ DECLARING TYPE CLASS INSTANCES > data Prod a b = a :* b > instance (Eq a, Eq b) > => Eq (Prod a b) where > (x :* y) == (x' :* y') = > (x == x' && y == y') or you can write: > data Cartesian a b = a :** b deriving Eq ------------------------------------------ pitfall: apparently the "where" can't be at the same indentation level as "instance", although I don't see why...