Similar presentations:
Типы. Классы
1. Типы. Классы.
Лектор:доцент каф. АОИ
Салмина Нина
Юрьевна
2. Типы, определяемые пользователем
Декларация данных: dataПеречислимые типы (конечное число нульарных конструкторов данных):
data Color = Red | Green | Blue | Yellow
-- четыре величины
Полиморфный тип с одним конструктором
Color, Point –имена
data Point a = Pt a a
(конструкторы) типов
Red, Green, Pt – конструкторы
Примеры:
данных
e1 :: Color
e3 :: Point Float
e1 = Red
e3 = Pt 2.0 3.0
e2 :: [Color]
e4 :: Point (Point Int)
e2 = [Red, Blue]
e4 = Pt (Pt 1 2) (Pt 3 4)
Конструктор типа и конструктор данных могут иметь одно имя:
data Point a = Point a a
3. Типы, определяемые пользователем
Выражение deriving Showдает возможность печатать значения новых типов:
Примеры:
data Color = Red | Green | Blue | Yellow deriving Show
data Point a = Pt a a deriving Show
e1 :: Color
e3 :: Point Float
e1 = Red
e3 = Pt 2.0 3.0
e2 :: [Color]
e4 :: Point (Point Int)
e2 = [Red, Blue]
e4 = Pt (Pt 1 2) (Pt 3 4)
> e1
Red
> e4
Pt (Pt 1 2) (Pt 3 4)
4. Рекурсивные типы
Тип для бинарных деревьев:data Tree a = Leaf a | Branch (Tree a) (Tree a)
deriving Show
вершины дерева – либо листья, содержащие
величину типа а, либо внутренними узлами,
содержащими два поддерева
5. Примеры функций для работы с бинарными деревьями
Отображение дерева в список листьев:fringe :: Tree a -> [a]
fringe (Leaf x) = [x]
fringe (Branch left right) = fringe left ++ fringe right
Имеют ли два дерева одну и ту же форму:
sameShape :: Tree a -> Tree b -> Bool
sameShape (Leaf x) (Leaf y) = True
sameShape (Branch l1 r1) (Branch l2 r2) =
sameShape l1 l2 && sameShape r1 r2
sameShape x y = False
6. Клиент. Описание данных
-- три типа клиентов:-- 1. правительственные организации, иденцифицируемые по названиям
-- 2. компании: название, идентификационный номер, данные контактного лица с
указанием его места в иерархии компании
-- 3. отдельные клиенты: фамилия, имя, желание получать в дальнейшем
информацию о предложениях и скидках
data Client = GovOrg String
| Company String Integer String String
| Individual String String Bool
deriving Show
-- Client - название типа
-- GovOrg, Company, Individual - имена конструкторов + типы их аргументов
Разные конструкторы – для построения разных вариантов значений!
7. Создание значений типа Client
data Client = GovOrg String| Company String Integer String String
| Individual String String Bool
deriving Show
Для создания значений типа Client указывается имя конструктора
и значения аргументов в том порядке, в котором эти аргументы
появляются в объявлении:
*Main> Individual “Ivanov" “Ivan" True
Individual “Ivanov" “Ivan" True
*Main> Company “IT co" 342 “Petrov" “Director”
Company “IT co" 342 “Petrov" “Director”
8. Client: унификация информации о людях
data Client = GovOrg String| Company String Integer Person String
| Individual Person Bool
deriving Show
data Person = Person String String
deriving Show
-- !!! ВАЖНО! внутри модуля ВСЕ конструкторы должны иметь разные
имена: даже в разных типах должны быть разные имена
конструкторов!
-- НО! имя типа и имя конструктора могут совпадать
*Main> Company “Co_pravo" 123 (Person "Ivanov" "Ivan") "director"
Company “Co_pravo" 123 (Person "Ivanov" "Ivan") "director"
9. Client: Функция выбора имени компании/клиента
clientName :: Client -> StringclientName (GovOrg name) = name
clientName (Company name _ _ _ ) = name
clientName (Individual (Person fName lName) _ )
= fName ++ " " ++ lName
*Main> clientName (Individual (Person “Ivanov" “Ivan") False)
“Ivanov Ivan"
10. Client: Функция выбора имени компании/клиента
Что будет, если функция рассмотрит не все случаи?clientName :: Client -> String
clientName (Company name _ _ _ ) = name
*Main> clientName (Individual (Person "aaa" "sss") False)
"*** Exception: D:\\UCH\Хаскел\data.hs:37:1-39: Non-exhaustive
patterns in function clientName
Часто встречается на практике
11. Встроенный тип Maybe («может быть») имеет только два вида значения:
data Maybe a = Nothing| Just a
Nothing – пустой конструктор (функция не имеет ничего
подходящего)
Just – непустой конструктор с параметром типа а
Используется для отслеживания различных
ошибочных ситуаций:
firstElem [ ] = Nothing
firstElem (x:xs) = Just x
12. Client: выбор имени компании (если это не компания – «ничего»)
clientNameN :: Client -> Maybe StringclientNameN (Company name _ _ _ ) = Just name
clientNameN ( _ ) = Nothing
*Main> clientNameN (Company "zzz" 12 (Person "aaa" "sss") "qqq")
Just "zzz"
*Main> clientNameN (Individual (Person "aaa" "sss") False)
Nothing
Подобные функции называются «частичными»
13. Client: еще функции
--функция, определяющая ответственность (должность) клиента:responsibility :: Client -> String
responsibility (Company _ _ _ x) = x
responsibility _ = "Unknowm"
--особый статус клиента: если он директор, или если его имя "Mr.
Boss"
specialClient :: Client -> Bool
specialClient x | "Mr. Boss" == clientName x = True
specialClient x | responsibility x == "Director" = True
specialClient _ = False
Или:
specialClient x | "Mr. Boss" == clientName x = True
| responsibility x == "Director" = True
| otherwise = False
14. Проверка статуса клиента
asas1 = Individual (Person "aaa" "sss") Falseasas2 = Company "eee" 123 (Person "aa" "xx") "Director"
asas3 = GovOrg "Mr. Boss"
*Main> specialClient asas1
False
*Main> specialClient asas2
True
*Main> specialClient asas3
True
15. Ad-hoc полиморфизм
Специальный полиморфизм (ad-hoc polimorfism)позволяет выразить тот факт, что
определенные типы проявляют общее для
них поведение.
Другое название - перегрузка
Примеры полиморфизма ad-hoc:
- Численные операторы (+, -, *) работают на числах
различных типов
- Логические операторы ==, >, < работают не только на
числах, но и на многих других типах
16. Классы типов
Классы типов обеспечивают структурныйспособ для управления полиморфизмом
ad-hoc.
Позволяют декларировать, какие типы есть
экземпляры какого класса, а также
обеспечивают определения перегруженных
операций, ассоциированных с классом.
17. Объявление класса
class Имя класса переменная whereфункция1 :: тип1
...
функцияN :: типN
определения_предлагаемые_по_умолчанию
18. Класс типов для определения равенства
class Eq a where(==), (/=) :: a -> a -> Bool
x /= y = not (x==y)
Eq – имя класса
==, /= - операторы класса
«тип а есть экземпляр класса Eq, если существуют
операторы (==), (/=) подходящего типа,
определенные для элементов класса а»
19. Сравнение типов, определяемых пользователем, на равенство
data Color = Red | Green | Blue | Yellow deriving Showdata Point a = Pt a a deriving Show
e1 :: Color
e3 :: Point Float
e1 = Red
e3 = Pt 2.0 3.0
e2 :: [Color]
e4 :: Point (Point Int)
e2 = [Red, Blue]
e4 = Pt (Pt 1 2) (Pt 3 4)
> e1 == Red
<interactive>:1:1: error:
* No instance for (Eq Color) arising from a use of `=='
* In the expression: e1 == Red
In an equation for `it': it = e1 == Red
20. Сравнение типов, определяемых пользователем, на равенство
data Color = Red | Green | Blue | Yellow deriving (Eq, Show)data Point a = Pt a a deriving (Show,Eq)
e1 :: Color
e3 :: Point Float
e1 = Red
e3 = Pt 2.0 3.0
e2 :: [Color]
e4 :: Point (Point Int)
e2 = [Red, Blue]
e4 = Pt (Pt 1 2) (Pt 3 4)
> e1 == Red
True
> e2 == [ ]
False
21. Равенство для бинарных деревьев
data Tree a = Leaf a | Branch (Tree a) (Tree a)deriving Show
Как сравнивать?
22. Декларация экземпляра
instance Имя_класса тип whereфункция1 = … -- тело функции
...
функцияN = … -- тело функции
Для типов, определяемых пользователем:
instance (Имя_класса тип) =>
Имя_класса (Тип_пользователя тип) where
…
Знак наследования
23. Равенство для бинарных деревьев
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Showinstance (Eq a) => Eq (Tree a) where
(Leaf a) == (Leaf b) = a == b
(Branch l1 r1) == (Branch l2 r2) = (l1 == l2) && (r1 == r2)
tree1,tree2 :: Tree Int
tree1 = Branch (Leaf 1) (Branch (Leaf 2) (Leaf 3))
tree2 = Branch (Leaf 1) (Branch (Leaf 2) (Leaf 3))
*Main> tree1 == tree2
True
24. Сравнение типов, определяемых пользователем
Классовое расширение: существует класс Ord, которыйнаследует все операции из Eq, но дополнительно имеет
операции сравнения и функции минимума и максимума:
class (Eq a) => Ord a where
(<), (<=), (>=), (>) :: a -> a -> Bool
max, min :: a -> a -> a
Eq есть суперкласс для Ord (Ord есть подкласс Eq): любой
тип, являющийся экземпляром Ord, должен быть
экземпляром Eq
Как следствие – методы для операций подкласса могут
использовать методы суперкласса
25. Сравнение типов, определяемых пользователем
data Color = Red | Green | Blue | Yellow deriving (Eq, Ord, Show)data Point a = Pt a a deriving (Eq, Ord, Show)
q1 :: Color
q1 = Red
q6 :: ([Color], Int, Point Int)
q6 = ([Red, Yellow], 34, Pt 5 5)
*Main> q6 > ([Red, Yellow], 34, Pt 5 1)
True
*Main> q6 < ([Blue, Yellow], 34, Pt 5 5)
True
*Main> q1 < Blue
True
*Main> "Red" < "Blue"
False
26. Сравнение типов, определяемых пользователем
Тип Data: число, месяц, годdata Data a = Data (a,a,a) deriving (Eq,Show,Ord)
Неверное сравнение дат:
> Data (31,2,1000) < Data (2,12,2022)
False
Необходимо решить следующий вопрос: как определить
действительное поведение ‘<‘ на элементах типа Data?
Для этого используется декларация экземпляра: instance
27. Определение метода ‘<‘ для типа Data
Определение метода ‘<‘ для типаData
data Data a = Data (a,a,a) deriving (Eq,Show)
instance (Ord a) => Ord (Data a) where
Data (a1,b1,c1) < Data (a2,b2,c2) =
(c1 < c2 ) ||
((c1 == c2) && (b1 < b2)) ||
((c1 == c2) && (b1 == b2) && (a1<a2))
«Тип Data есть экземпляр типа класса Ord и для него
определен метод, соответствующий операции ‘<‘»
> Data (31,2,1000) < Data (2,12,2022)
True
28. Определение метода ‘<‘ для типа Data
Определение метода ‘<‘ для типаData
data Data a = Data (a,a,a) deriving (Eq,Show)
instance (Ord a) => Ord (Data a) where
Data (a1,b1,c1) < Data (a2,b2,c2) =
Предупреждение!!!
‘<=‘
(c1 < c2 ) ||
((c1 == c2) && (b1 < b2)) ||
((c1 == c2) && (b1 == b2) && (a1<a2))
«Тип Data есть экземпляр типа класса Ord и для него
определен метод, соответствующий операции ‘<‘»
> Data (31,2,1000) < Data (2,12,2022)
True
29. Определение корректного сравнения для типа Data
data Data a = Data (a,a,a) deriving (Eq,Show)instance (Ord a) => Ord (Data a) where
Data (a1,b1,c1) < Data (a2,b2,c2) =
(c1 < c2 ) ||
((c1 == c2) && (b1 < b2)) ||
((c1 == c2) && (b1 == b2) && (a1<a2))
Data a <= Data b = (Data a < Data b) || (Data a == Data b)
Теперь сравнение дат будет корректно для любых знаков:
> Data (31,2,1000) > Data (2,12,2022)
False
> Data (21,1,1) <= Data (1,1,12)
True
30. Другой вариант описания типа Data
data Month = January | February | March | April | May | June | July| … deriving (Eq,Ord,Show)
data Data1 a b = Data1 (a, b, a) deriving (Eq,Show)
instance (Ord a, Ord b) => Ord (Data1 a b) where
Data1 (a1,b1,c1) < Data1 (a2,b2,c2) = (c1 < c2 ) ||
((c1 == c2) && (b1 < b2)) ||
((c1 == c2) && (b1 == b2) && (a1<a2))
Data1 (a1,b1,c1) <= Data1 (a2,b2,c2) = (c1 < c2 ) ||
((c1 == c2) && (b1 < b2)) ||
((c1 == c2) && (b1 == b2) && (a1<a2)) ||
((c1 == c2) && (b1 == b2) && (a1==a2))
31. Сортировка дат типа Data
data Month = January | February | March | April | May | June | July| … deriving (Eq,Ord,Show)
data Data1 a b = Data1 (a, b, a) deriving (Eq,Show)
*Main> sort [Data (12,2,2000),Data (1,2,2000),
Data (12,2,1298),Data (24,5,2000)]
[Data (12,2,1298), Data (1,2,2000), Data (12,2,2000),
Data (24,5,2000)]
32. Создание собственного класса «почти равно»
class EqNear a whereeq :: a -> a -> Bool
instance EqNear Int where
eq x y = abs (x-y) < 3 -- "почти равно"
instance EqNear Float where
eq x y = abs (x-y) < 0.1
Внимание!!! Числа в языке Hascell являются перегруженными
– выражение «eq 3 4» вызовет ошибку!
Необходимо явно указывать тип:
*Main> eq (3::Int) (4::Int)
True
33. Создание собственного класса «почти равно»
class EqNear a whereeq :: a -> a -> Bool
instance EqNear Int where
eq x y = abs (x-y) < 3 -- "почти равно"
instance EqNear Float where
eq x y = abs (x-y) < 0.1
При использовании данного метода в функциях, где явно
указан тип переменных, ошибки не будет:
dd1 :: Int
*Main> eq dd1 dd2
dd1 = 3
True
dd2 :: Int
dd2 = 4
34. «почти равно» для бинарных деревьев
data Tree a = Leaf a | Branch (Tree a) (Tree a) deriving Showinstance (EqNear a) => EqNear (Tree a) where
eq (Leaf a) (Leaf b) = eq a b
eq (Branch l1 r1) (Branch l2 r2) = (eq l1 l2) && (eq r1 r2)
tree1,tree2 :: Tree Int
tree1 = Branch (Leaf 1) (Branch (Leaf 2) (Leaf 3))
tree2 = Branch (Leaf 2) (Branch (Leaf 2) (Leaf 2))
*Main> eq tree1 tree2
True
35. Некоторые ограничения на декларацию экземпляров
Не может быть больше одной декларации для даннойкомбинации типа данных и класса;
Если тип декларируется как экземпляр какого-то класса, то
он становится экземпляром всех суперклассов этого
класса;
Декларация экземпляра не обязана содержать описание
метода для каждого оператора данного класса. Если метод
не описан в декларации экземпляра и отсутствует его
описание по умолчанию, то при его вызове может
возникнуть ошибка исполнения.