Info on typeclasses and types

This commit is contained in:
David Sampson 2019-11-04 10:51:48 -06:00 committed by GitHub
parent f9d74a3191
commit f276866777
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -293,7 +293,13 @@ foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16
-- 7. Data Types
----------------------------------------------------
-- Here's how you make your own data type in Haskell
-- A data type is declared with a 'type constructor' on the left
-- and one or more 'data constructors' on the right, separated by
-- the pipe | symbol. This is a sum/union type. Each data constructor
-- is a (possibly nullary) function that creates an object of the type
-- named by the type constructor.
-- This is essentially an enum
data Color = Red | Blue | Green
@ -304,7 +310,57 @@ say Red = "You are Red!"
say Blue = "You are Blue!"
say Green = "You are Green!"
-- Your data types can have parameters too:
-- Note that the type constructor is used in the type signature
-- and the data constructors are used in the body of the function
-- Data constructors are primarily pattern-matched against
-- This next one is a traditional container type holding two fields
-- In a type declaration, data constructors take types as parameters
-- Data constructors can have the same name as type constructors
-- This is common where the type only has a single data constructor
data Point = Point Float Float
-- This can be used in a function like:
distance :: Point -> Point -> Float
distance (Point x y) (Point x' y') = sqrt $ dx + dy
where dx = (x - x') ** 2
dy = (y - y') ** 2
-- Types can have multiple data constructors with arguments, too
data Name = Mononym String | FirstLastName String String | FullName String String String
-- To make things clearer we can use record syntax
data Point2D = CartesianPoint2D { x :: Float, y :: Float } | PolarPoint2D { r :: Float, theta :: Float }
myPoint = CartesianPoint2D { x = 7.0, y = 10.0 }
-- Using record syntax automatically creates accessor functions (the name of the field)
xOfMyPoint = x myPoint
-- xOfMyPoint is equal to 7.0
-- Record syntax also allows a simple form of update
myPoint' = myPoint { x = 9.0 }
-- myPoint' is CartesianPoint2D { x = 9.0, y = 10.0 }
-- Even if a type is defined with record syntax, it can be declared like
-- a simple data constructor. This is fine:
myPoint'2 = CartesianPoint2D 3.3 4.0
-- It's also useful to pattern match data constructors in `case` expressions
distanceFromOrigin x = case x of (CartesianPoint2D x y) -> sqrt $ x ** 2 + y ** 2
(PolarPoint2D r _) -> r
-- Your data types can have type parameters too:
data Maybe a = Nothing | Just a
@ -313,8 +369,93 @@ Just "hello" -- of type `Maybe String`
Just 1 -- of type `Maybe Int`
Nothing -- of type `Maybe a` for any `a`
-- For convenience we can also create type synonyms with the 'type' keyword
type String = [Char]
-- Unlike `data` types, type synonyms need no constructor, and can be used
-- anywhere a synonymous data type could be used. Say we have the
-- following type synonyms and items with the following type signatures
type Weight = Float
type Height = Float
type Point = (Float, Float)
getMyHeightAndWeight :: Person -> (Height, Weight)
findCenter :: Circle -> Point
somePerson :: Person
someCircle :: Circle
distance :: Point -> Point -> Float
-- The following would compile and run without issue, even though it does not make
-- sense semantically, because the type synonyms reduce to the same base types
distance (getMyHeightAndWeight somePerson) (findCenter someCircle)
----------------------------------------------------
-- 8. Haskell IO
-- 8. Typeclasses
----------------------------------------------------
-- Typeclasses are one way Haskell does polymorphism
-- They are similar to interfaces in other languages
-- A typeclass defines a set of functions that must work on any type that is in
-- that typeclass.
-- The Eq typeclass is for types whose instances can be tested for equality with one another
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
-- This defines a typeclass that requires two functions, (==) and (/=)
-- It also declares that one function can be declared in terms of another
-- So it is enough that *either* the (==) function or the (/=) is defined
-- And the other will be 'filled in' based on the typeclass definition
-- To make a type a member of a type class, the instance keyword is used
instance Eq TrafficLight where
Red == Red = True
Green == Green = True
Yellow == Yellow = True
_ == _ = False
-- Now we can use (==) and (/=) with TrafficLight objects
canProceedThrough :: TrafficLight -> Bool
canProceedThrough t = t /= Red
-- You can NOT create an instance definition for a type synonym
-- Functions can be written to take typeclasses with type parameters, rather than types,
-- assuming that the function only relies on features of the typeclass
isEqual (Eq a) => a -> a -> Bool
isEqual x y = x == y
-- Note that x and y MUST be the same type, as they are both defined as being of type parameter 'a'
-- A typeclass does state that different types in the typeclass can be mixed together
-- So `isEqual Red 2` is invalid, even though 2 is an Int which is an instance of Eq, and Red is
-- a TrafficLight which is also an instance of Eq
-- Other common typeclasses are:
-- Ord for types that can be ordered, allowing you to use >, <=, etc.
-- Read for types that can be created from a string representation
-- Show for types that can be converted to a string for display
-- Num, Real, Integral, Fractional for types that can do mathematical calculation
-- Enum for types that can be stepped through
-- Bounded for types with a maximum and minimum
-- Haskell can automatically make types part of Eq, Ord, Read, Show, Enum, and Bounded
-- with the `deriving` keyword at the end of the type declaration
data Point = Point Float Float deriving (Eq, Read, Show)
-- In this case it is NOT necessary to create an 'instance' definition
----------------------------------------------------
-- 9. Haskell IO
----------------------------------------------------
-- While IO can't be explained fully without explaining monads,
@ -395,7 +536,7 @@ main'' = do
----------------------------------------------------
-- 9. The Haskell REPL
-- 10. The Haskell REPL
----------------------------------------------------
-- Start the repl by typing `ghci`.