Haskell
E N D
Presentation Transcript
Haskell Chapter 7
Topics • Defining data types • Exporting types • Type parameters • Derived instances • Type synonyms • Either • Type classes • Not covered • record syntax • recursive data structures • subclassing • parameterized types as instances of type classes • Yes-No type class (emulate JavaScript-like behavior) • Functor type class
Define a new data type data Bool = False | True • data keyword indicates a new data type (Bool is not new, just an example) • False and True are value constructors • | is “or” – Bool can be False or True • Type name and value constructors must start with capital letter • Value constructors are actually functions that return a value of a data type
Shape example -- Circle parms coordinates and radius -- Rectangle parms upper left and lower right coordinates data Shape = Circle Float FloatFloat | Rectangle Float FloatFloatFloat • *Main> :t Circle • Circle :: Float -> Float -> Float -> Shape • *Main> :t Rectangle • Rectangle :: Float -> Float -> Float -> Float -> Shape
Shape continued area :: Shape -> Float area (Circle _ _ r) = pi * r ^2 area (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs y2 - y1) • Notice the pattern match against constructor • *Main> let c = Circle 3 4 5 • *Main> area c • 78.53982 • But we don’t know how to show a circle (yet) • *Main> c • <interactive>:15:1: • No instance for (Show Shape) • arising from a use of `print' • Possible fix: add an instance declaration for (Show Shape) • In a stmt of an interactive GHCi command: print it remember $is function application
Updating shape to be displayed data Shape = Circle Float FloatFloat | Rectangle Float FloatFloatFloat deriving (Show) • *Main> let c = Circle 3 4 5 • *Main> c • Circle 3.0 4.0 5.0
Improving Shape with a Point data type data Point = Point Float Float deriving (Show) data Shape = Circle Point Float | Rectangle Point Point deriving (Show) area :: Shape -> Float area (Circle _ r) = pi * r ^2 area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs y2 - y1) • *Main> area (Rectangle (Point 0 0) (Point 100 100)) • 10000.0
Another method for Shapes nudge :: Shape -> Float -> Float -> Shape nudge (Circle (Point x y) r) dxdy = Circle (Point (x+dx) (y+dy)) r nudge (Rectangle (Point x1 y1) (Point x2 y2)) dxdy = Rectangle (Point (x1+dx) (y1+dy)) (Point (x2+dx) (y2+dy)) • *Main> nudge (Circle (Point 34 34) 10) 5 10 • Circle (Point 39.0 44.0) 10.0
Exporting shape module Shapes ( Point(..) , Shape(..) , area , nudge ) where • Shape(..) exports all value constructors (in this case Circle and Rectangle). • Makes it easy to add more shapes later (OCP) • If just export Shape, not Shape(..), can’t pattern match (Programming Languages: support for encapsulation)
Type Parameters • A value constructors takes some parameters, produces a new value (e.g., Circle takes 3 values, returns a circle value) • A type constructor takes a type as a parameter, returns a new type • Maybe type constructor defined as: data Maybe a = Nothing | Just a • Can’t have just Maybe… needs to be Maybe something • Why is this useful? Strong typing. In Java, a function might return a Point or null. This is not possible in Haskell. So if a function may or may not produce a value, then the return type is Maybe something (e.g., Maybe Point) • Because of type inference, the parameter to Maybe is often a literal value.. Haskell figures out what it is. • Maybe ‘a’ = Maybe Char
Usage • Due to type inference, often don’t pass parameters to type constructors explicitly • If a value is Just ‘a’, Haskell infers type as Maybe Char • Concrete type either doesn’t take any type parameters, e.g., Int, Bool OR has filled type parameters (Maybe Char) • List type takes a parameter, returns concrete type • [Int] is an example
Play with it • *Main> Just "Haha" • Just "Haha" • *Main> Just 84 • Just 84 • *Main> :t Just "Haha" • Just "Haha" :: Maybe [Char] • *Main> :t Just 84 • Just 84 :: Num a => Maybe a • *Main> :t Nothing • Nothing :: Maybe a • *Main> Just 10 :: Maybe Double • Just 10.0
Type class \= Java class • In Java, we use a class as a blueprint to create objects • In Haskell, you use type classes to make a data type, then think about how it can act • We do this with deriving • If types of all fields are part of a type class, then our new type can be part of a type class data Person = Person { name :: String, age :: Int } deriving (Eq, Show)
Example • *Shapes> let frodo = Person {name = "Frodo Baggins", age = 43} • *Shapes> let bilbo = Person {name = "Bilbo Baggins", age = 100} • *Shapes> bilbo • Person {name = "Bilbo Baggins", age = 100} • *Shapes> bilbo == frodo • False • *Shapes> let imposter = Person {name = "Frodo Baggins", age = 43} • *Shapes> frodo == imposter • True
Enum example data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Eq, Show, Ord, Read, Bounded, Enum) *Chap7> Wednesday Wednesday *Chap7> show Wednesday "Wednesday" *Chap7> read "Saturday" :: Day Saturday *Chap7> Saturday == Sunday False *Chap7> Monday `compare` Wednesday LT *Chap7> Saturday > Friday True *Chap7> minBound :: Day Monday *Chap7> maxBound :: Day Sunday *Chap7> let weekend = [Friday .. Sunday] *Chap7> weekend [Friday,Saturday,Sunday]
Type Synonyms • [Char] and String are type synonyms type PhoneNumber = String type Name = String type PhoneBook = [(Name, PhoneNumber)] inPhoneBook :: Name -> PhoneNumber -> PhoneBook -> Bool inPhoneBook name pnumberpbook = (name, pnumber) `elem` pbook Not covered: parameterized type synonyms
Could be Either • Use to encapsulate a value of one type or another • Is defined as: • data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show) • *Chap7> Right 20 • Right 20 • *Chap7> Left "Whoa" • Left "Whoa" • *Chap7> :t Right 'a' • Right 'a' :: Either a Char • *Chap7> :t Left True • Left True :: Either Bool b
Either with try • The try functions • try :: Exception e => IO a -> IO (Either e a)Source • Similar to catch, but returns an Either result which is (Right a) if no exception of type e was raised, or (Left ex) if an exception of type e was raised and its value is ex. If any other type of exception is raised than it will be propogated up to the next enclosing exception handler. • try a = catch (Right `liftM` a) (return . Left) http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Control-Exception.html#7
Usage • Maybe can be used if function might return a result or fail • Either can be used if there are multiple possible results • You’ll explore this more in the homework
Type Classes 102 • Type classes are sort of like interfaces: they define behavior • Types that can behave that way are made instances (just means they can use the functions associated with that type class) class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y) note the mutual recursion… only need to implement one!
Using a type class data TrafficLight = Red | Yellow | Green instance EqTrafficLight where Red == Red = True Green == Green = True Yellow == Yellow = True _ == _ = False instance Show TrafficLight where show Red = "Red Light" show Green = "Green Light" show Yellow = "Yellow Light"
Using the Traffic Light • *Chap7> Red • Red Light • *Chap7> Red • Red Light • *Chap7> Red == Red • True • *Chap7> Red == Green • False • *Chap7> Red `elem` [Red, Green, Yellow] • True