Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Переписывание
Переписывание контрольной 18 ноября
на 4 паре
ауд. 01 или там будет объявление
1
Задачи на дом и на
листке
2
goodNumbers
2: 5: 7: 22: 25: 27:52:55:57:
- >>= \i -> [10*i+2, 10*i+5, 10*i+7]
- [10*i+j | i <- goodNumbers, j <- [2,5,7]]
22:25:27:52:55:57:
приписать 2:5:7:
2:5:7: 22: 25: 27:52:55:57:
goodNumbers = 2:5:7:(goodNumbers >>= \i ->
[10*i+2, 10*i+5, 10*i+7])
3
ham
Richard Hamming: 2^i * 3^j * 5^k
1, 2, 3, 4, 6, 8, 9, 12, 16, 18, 24, …
map (*2) ham
2, 4, 6, 8, 12, 16, 18, 24 …
Не хватает только 1, 3, 9, 27 …
Как добавить?
merge!
ham = merge (map (*2) ham) ([3^n | i<-[0..] ])
Или, та же идея, но другой вариант:
ham = 1 : merge (map (*2) ham) (map (*3) ham) 4
Just as there are odors that dogs can smell and we cannot, as well as sounds that dogs can hear and we cannot, so too there are wavelengths of light we cannot see and flavors we cannot taste. Why then, given our brains wired the way they are, does the remark, "Perhaps there are thoughts we cannot think," surprise you?
Задачи на листочке
Тип (.)
sin . (`mod` 10) =
\x -> sin (x `mod` 10)
( -> ) -> ( -> ) -> ( -> )
(b->с) -> (a->b) -> (a->c)
(a->a)->a->a
func f x =
f (f x)
func f x = f (f (f x))
(a->a)->(a->a)
func f = f . f
func f = f . f . f
5
Классы
6
Дробиdata Ration = Rat Integer Integer
instance Ord Ration where
Rat n1 d1 < Rat n2 d2 = n1*d2 < n2*d1
--- Вспомните 6 класс! ---
Rat n1 d1 < Rat n2 d2 = if d1*d2 > 0
then n1*d2 < n2*d1 else n1*d2 > n2*d1
instance Eq Ration where
Rat n1 d1 == Rat n2 d2 = n1*d2 == n2*d1
instance Num Ration where
Rat n1 d1 + Rat n2 d2 = Rat (n1*d2 + n2*d1) (d1*d2)
Было бы здорово быть уверенным, что знаменатели всегда >0
Но в Хаскеле этого трудно добиться ((
Инкапсуляция в Хаскеле поддерживается не очень хорошо ((
7
Правила по умолчанию
В определении класса можно задавать правила
В instance можно их переопределять
class Shape a where
weight:: a->Double
weight s = area s * 10
instance Shape Square where
weight s = area s * 100
Полезное применение – связь < и > или == и /= и т.д.
class Ord
x < y = y > x
x > y = y < x
8
deriving
data Abc = … deriving Show
Определить show автоматически (как-то, нам не важно как)
Еще
Ord
Eq
Functor (Опция -XDeriveFunctor)
… и еще несколько
Можно писать несколько классов
data Abc = … deriving (Show, Ord, Eq)
См. также Datatype-generic programminghttp://www.haskell.org/haskellwiki/Generics
9
Замечания про полиморфизм
Полиморфизм: один код работает с разными типами.
В функциональном программировании выделяют два видаполиморфизма:
length
Параметрический полиморфизм. Можно использовать вообще с любыми типами
f x = area x / perim x
Ad hoc полиморфизм – типы должны принадлежать классу
Можно ли в одном списке хранить разные типы?
shapes = [Circle 10, Rect 3 4, Circle 7, Triang 1]
В обычном Haskell’е нет, но есть расширение
Existential types https://wiki.haskell.org/Existential_type
10
Еще немного про
функторы
11
fmap для Scheme
data Scheme a = R a | S (Scheme a) (Scheme a) | P (Scheme a) (Scheme a) deriving Show
instance Functor Scheme where
fmap f (R r) = R (f r)
fmap f (S a b) = S (fmap f a) (fmap f b)
fmap f (P a b) = P (fmap f a) (fmap f b)
doubleAll s = fmap (*2) s
S (R 3) (R 5) S (R 6) (R 10)
12
Законы для Functor
Что требуется от функции, чтобы она вела себя, как map?
Сформулировали законы:
1. fmap id t == t
2. fmap (f . g) t ==
fmap f (fmap g t)
(Компилятор про них не знает, за соблюдением должен следить сам программист)
Кстати, нарушить их не так просто…
Примеры нарушения?
Ну например, так мы можем нарушить 1 закон для списков.
map f (x:xs) = f x: f x: map f xs
А 2 закон?
Оказывается, если у fmapправильный тип и выполняется закон 1, то закон 2 точно будет выполняется!
parametricity или free theorem, потом пройдем
13
Чуть-чуть про связь ФП и теории
категорий
Законы
1. fmap id x == x
2. fmap f (fmap g x) == fmap (f . g) x
(Ну, например, fmap (*2) (fmap (*3) x) ==
fmap (*6) x
Перепишем в point-free стиле
fmap id == id
fmap (f.g) == fmap f . fmap g
То есть, законы означают, что fmap
fmap переводит id в id
fmap переводит композицию в композицию
На что похоже?
Например, линейные отображения - у нихf 0 = 0f (x+y) == f x + f y
Например, гомоморфизмы в теории группа
Есть наука, которая умеет рассуждать сразу и про линейные отображения, и про гомоморфизмы и про функторы. Про те общие законы, которые у них есть.
Теория категорий
Если интересно узнать про связь ФП и теории категорий:https://www.youtube.com/user/DrBartosz 14
Еще про >>=.
>>= для других типов
15
<=< для Maybe
(f <=< g) x =
let res = g x in
case res of
Nothing -> Nothing
Just y -> f y
16
Три поиска
Найти в списке:
первое число, меньше 5
первое число, больше 10
первое число, не равно 7
Вернуть сумму этих чисел, или [], если что-то не нашли
find cond [] = []
find cond (x:xs) =
if cond x
then [x]
else find cond xs
++ и length
zipWith, zipWith3
Можно использовать list comprehension!
f xs = [x+y+z | x<- find (<5) xs,
y<-find (>10) xs,
z<- find (/=7) xs]
Используя do
f xs = do
x <- find (<5) xs
y <- find (>10) xs
z <- find (/=7) xs
return (x+y+z) 17
«Выполнять до первой неудачи»
f xs = do
x <- find (<5) xs
y <- find (>10) xs
z <- find (/=7) xs
return (x+y+z)
Если пустой список обозначает неудачу поискато do (и >>=) – «выполнять до первой неудачи»
Какие функции нам бы еще хотелось выполнять до первой неудачи?
Конечно, Maybe
18
do для Maybe
>>= и return (и, следовательно, do) определены и для Maybe
Смысл такой же – «выполнять до первой неудачи»
Например:
1. Найти в xs число, больше 5
2. найти в ys число, большее 5
3. вернуть их произведение.
4. обернутое в Just. Если что-то не получится, вернуть Nothing.
do
x <- find (>5) xs
y <- find (>5) ys
return (x*y)
Проверки на Nothing делает за нас >>= 19
Зачем определяют >>=?
1. Чтобы можно было использовать что то вроде нашего superMap
Например, для Scheme - можно определить >>=, как функцию, которая:
заменяет резисторы в схеме на что-то
но не на другие резисторы, как fmap, а заменяет резистор на схему
Например, пусть мы хотим:
все резисторы R x заменить на два таких же соединенных параллельно.
Например, R 6 P (R 6) (R 6)
Если мы напишем для Scheme >>=, то это можно будет сделать так:
sch >>= \x -> P (R x) (R x)
И тогда, например для
S (R 3) (R 5)
получится
S (P (R 3) (R 3)) (P (R 5) (R 5))20
Более важное использование
2. Чтобы можно было последовательно вызывать функции и при этом автоматически делать что-то дополнительное. Примерно как для Maybe и >>= автоматически проверяется Nothing
21
>>= для задания дополнительных действий при
последовательных вычислениях
f xs = do
x <- find (<5) xs
y <- find (>10) xs
z <- find (/=7) xs
return (x+y+z)
Т.е. мы описываем некоторые действия
Которые должны выполняться одно за другим
И при этом должно автоматически происходить что-то дополнительное
Примерно как если бы в обычном языке мы могли бы переопределить точку с запятой
22
Вычислить find (<5) xs, потом вычислить find (>10) xs, потомвычислить find (/=7) xs
И, кроме этого выполнять дополнительные действия(проверять, удачно ли завершились вызовы)
Какую бы еще монаду определить?
Что бы еще сделать дополнительное при последовательных вычислениях?
Считать деньги за функции («тридевятое царство»)
f x = do
y <- sin39 x
z <- exp39 x
return (y+z)
Подсчет суммы денег будет делать за нас >>=
23
Про д.з.:
пока опишем ‘почти монаду’
Опишем ‘почти монаду’
>>>= вместо >>=
return1 вместо return
f x =
sin39 x >>>= \y ->
exp39 x >>>= \z ->
return1 (y+z)
Просто чтобы нас не отвлекали всякие заклинания про классы, instance и т.д.
А совсем монады в следующий раз
24
Continuations
25
findInLists
Без failure continuation как-то так:
findInLists cond (xs:xss) err = let
res = findCont cond xs err
in if res /= err
then res
else findInLists cond xss err
findInLists cond [] err = err
С использованием failure continuation гораздо короче
findInLists cond (xs:xss) err =
findCont cond xs (
findInLists cond xss err
)
Обошлись без if!
См. на эту тему http://degoes.net/articles/destroy-all-ifs 26
Что делать, если не нашли
Еще пример
Найти первое число, большее 1000, а если его нет, то первое число большее 500, а если и его нет, то первое число большее 100 (а если и его нет, вернуть 0):
find (>1000) xs
(
find (>500) xs
(
find (>100) xs 0
)
)
27
На листочке
28
Как вернуть позицию в списке?
Сейчас будем считать, что наш find всегда что-то находить. Но остается другая проблема:
Когда мы ищем что-то в списке, хотелось бы вернуть не просто значение, а еще как-то и то место, на котором мы его нашли.
Например, хотелось бы написать find, чтобы его можно было вызвать три раза и найти третий элемент в списке, удовлетворяющий данному условию
Какой должен быть интерфейс у такого find?
Распостраненный вариант: возвращать пару (значение, еще не просмотренный хвост списка)
29
На листочке
1. Описать такой find
find (>3) [2,1,4,2,7,8] (4, [2,7,8])
find (>10) [2,1,4,2,7,8] что угодно, например, error или undefined
2.
C помощью find из пункта 1, вернуть второе число, большее 3
30