...
 
Commits (2)
---------------------------------------------
-- 1. Eq: defines equality and inequality. --
---------------------------------------------
class Eq a where
(==), (/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
-- Minimum complete definition: (==) OR (/=)
-- GHCI examples:
-- :t (==)
-- :t (/=)
-- 2 == 3
-- 3 == 3
-- Example instance...
data Color = Red | Green | Blue
instance Eq Color where
(==) Red Red = True
(==) Green Green = True
(==) Blue Blue = True
(==) _ _ = False
-- Alternatively, use automatic derivation!
data Color2 = Red2 | Green2 | Blue2
deriving (Eq)
------------------------------------------------
-- 2. Ord: defines functions that compare values.
------------------------------------------------
-- Built in ordering type:
data Ordering = LT | EQ | GT
-- Typeclass definition.
class (Eq a) => Ord a where
compare :: a -> a -> Ordering
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
compare x y | x == y = EQ -- a must have implemented ==
| x <= y = LT
| otherwise = GT
x <= y = compare x y /= GT
x < y = compare x y == LT
x >= y = compare x y /= LT
x > y = compare x y == GT
max x y | x <= y = y
| otherwise = x
min x y | x <= y = x
| otherwise = y
-- Minimum complete definition:
-- compare OR <=
-- GHCI examples
-- :t compare
-- :t (<=)
-- compare 2.0 2.1
-- compare 'a' 'b'
-- 2.0 <= 2.1
-- Hoogle Ord
-- Look at laws of ORD.
-- Hoogle: Ord a => [a] -> [a]
-- Example instance
instance Ord Color where
compare Red Red = EQ
compare Green Green = EQ
compare Blue Blue = EQ
compare Red Green = LT
compare Red Blue = LT
compare Green Blue = LT
compare _ _ = GT
-- ...
-- Deriving Ord works here.
-------------------------------------
-- 3. Num: the basc numeric typeclass
-------------------------------------
class Num a where
(+), (-), (*) :: a -> a -> a
-- | Unary negation.
negate :: a -> a
-- | Absolute value.
abs :: a -> a
-- | Sign of a number.
signum :: a -> a
-- | Conversion from an 'Integer'.
fromInteger :: Integer -> a
x - y = x + negate y
negate x = 0 - x
-- Minimal complete definition: (+), (*), abs, signum, fromInteger, and negate (or (-)).
-----------------------------------------------------
-- 4. Enum: operations on sequentially ordered types.
-----------------------------------------------------
class Enum a where
succ, pred :: a -> a -- Successor / predecessor of a value
toEnum :: Int -> a -- Convert from an Int
fromEnum :: a -> Int -- Convert to an Int
enumFrom :: a -> [a] -- [n..]
enumFromThen :: a -> a -> [a] -- [n,n'..]
enumFromTo :: a -> a -> [a] -- [n..m]
enumFromThenTo :: a -> a -> a -> [a] -- [n,n'..m]
succ = toEnum . (+ 1) . fromEnum
pred = toEnum . (subtract 1) . fromEnum
enumFrom x = map toEnum [fromEnum x ..]
enumFromThen x y = map toEnum [fromEnum x, fromEnum y ..]
enumFromTo x y = map toEnum [fromEnum x .. fromEnum y]
enumFromThenTo x1 x2 y = map toEnum [fromEnum x1, fromEnum x2 .. fromEnum y]
-- Minimum complete definition:
-- toEnum and fromEnum
-- Example instance:
data Color = Red | Green | Blue
deriving (Read, Show, Eq, Ord, Enum)
-- GHCI examples
-- :t toEnum
-- :t fromEnum
-- take 10 $ enumFromThen 2 4
-- take 10 $ enumFromTo 1 100
----------------------------------------------------------------
-- 5. Read and Show: converting strings to values and vice versa
----------------------------------------------------------------
-- This is the machinery we invoke when we type
-- "deriving Show" after declaring a custom type.
-- A little complicated, and the details don't matter too much.
type ReadS a = String -> [(a,String)]
type ShowS = String -> String
class Read a where
readsPrec :: Int -> ReadS a
readList :: ReadS [a]
-- ... default decl for readList given in Prelude
-- Minimal complete definition: readsPrec or readPrec. Complicated parsing logic. Often easier to use Parsec.
class Show a where
showsPrec :: Int -> a -> ShowS
show :: a -> String
showList :: [a] -> ShowS
showsPrec _ x s = show x ++ s
show x = showsPrec 0 x ""
-- ... default decl for showList given in Prelude
-- Minimal complete definition: showsPrec or show
-- Other important typeclasses
-- Integral (Int, Integer)
-- Fractional (Double)
-- Floating (Double)
-- RealFrac (round, truncate)
......@@ -4,17 +4,18 @@ main :: IO ()
main = do
putStrLn "hello world"
-- Example eq function.
-- Source: RWH, Chapter 6
-- Suppose we define a new type, Color.
data Color = Red | Green | Blue
-- We might want to define an equality check for it.
colorEq :: Color -> Color -> Bool
colorEq Red Red = True
colorEq Green Green = True
colorEq Blue Blue = True
colorEq _ _ = False
-- Suppose we wrote a function to test for equality on strings.
-- Suppose that (==) didn't exist.
-- We might implement a function, stringEq as follows.
stringEq :: [Char] -> [Char] -> Bool
stringEq [] [] = True
......@@ -22,10 +23,19 @@ stringEq (x:xs) (y:ys) = (x == y) && stringEq xs ys
stringEq _ _ = False
-- Example typeclasses
-- But this is super inefficient - we have to write separate functions
-- for each notion of "equality" that we want to encode.
-- Introducing typeclasses:
-- This allows us to give different definitions of a function
-- for different types.
-- These are not classes, similar to the notion of _interfaces_ in Java.
-- Example typeclass: BasicEq
class BasicEq a where
isEqual :: a -> a -> Bool
-- Example _instance_ of the BasicEq typeclass on booleans.
instance BasicEq Bool where
isEqual True True = True
isEqual False False = True
......@@ -33,8 +43,10 @@ instance BasicEq Bool where
-- isEqual True True now works
-- isEqual "Hi" "Hi2" will not
--
-- Expanding on this: we can define a more sophisticated typeclass
-- with multiple functions. For a type to be in the "BasicEq2" type class,
-- it must implement _one of_ "isEqual2" and "isNotEqual2".
class BasicEq2 a where
isEqual2 :: a -> a -> Bool
isEqual2 x y = not (isNotEqual2 x y)
......@@ -42,13 +54,16 @@ class BasicEq2 a where
isNotEqual2 :: a -> a -> Bool
isNotEqual2 x y = not (isEqual2 x y)
-- Pattern match on constructors
-- We can make `Color` an instance of
-- `BasicEq2` by implementing `isEqual2`.
-- Compiler is really smart, it will figure out the other.
instance BasicEq2 Color where
isEqual2 Red Red = True
isEqual2 Green Green = True
isEqual2 Blue Blue = True
isEqual2 _ _ = False
-- Want to spend time
-- Look at source of Eq
-- :info
-- Look at docs
......@@ -64,11 +79,3 @@ instance Show Color where
-- Automatic typeclass derivation!
data Color2 = Red2 | Green2 | Blue2
deriving (Read, Show, Eq, Ord)
-- Show that eq is automatically derived.
readShowDouble = do
putStrLn "Please enter a Double:"
inpStr <- getLine
let inpDouble = (read inpStr)::Double
putStrLn ("Twice " ++ show inpDouble ++ " is " ++ show (inpDouble * 2))