30
Переписывание Переписывание контрольной 18 ноября на 4 паре ауд. 01 или там будет объявление 1

План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Переписывание

Переписывание контрольной 18 ноября

на 4 паре

ауд. 01 или там будет объявление

1

Page 2: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Задачи на дом и на

листке

2

Page 3: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*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

Page 4: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

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?

Page 5: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Задачи на листочке

Тип (.)

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

Page 6: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Классы

6

Page 7: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Дроби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

Page 8: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Правила по умолчанию

В определении класса можно задавать правила

В 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

Page 9: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

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

Page 10: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Замечания про полиморфизм

Полиморфизм: один код работает с разными типами.

В функциональном программировании выделяют два видаполиморфизма:

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

Page 11: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Еще немного про

функторы

11

Page 12: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

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

Page 13: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Законы для 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

Page 14: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Чуть-чуть про связь ФП и теории

категорий

Законы

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

Page 15: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Еще про >>=.

>>= для других типов

15

Page 16: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

<=< для Maybe

(f <=< g) x =

let res = g x in

case res of

Nothing -> Nothing

Just y -> f y

16

Page 17: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Три поиска

Найти в списке:

первое число, меньше 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

Page 18: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

«Выполнять до первой неудачи»

f xs = do

x <- find (<5) xs

y <- find (>10) xs

z <- find (/=7) xs

return (x+y+z)

Если пустой список обозначает неудачу поискато do (и >>=) – «выполнять до первой неудачи»

Какие функции нам бы еще хотелось выполнять до первой неудачи?

Конечно, Maybe

18

Page 19: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

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

Page 20: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Зачем определяют >>=?

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

Page 21: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Более важное использование

2. Чтобы можно было последовательно вызывать функции и при этом автоматически делать что-то дополнительное. Примерно как для Maybe и >>= автоматически проверяется Nothing

21

Page 22: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

>>= для задания дополнительных действий при

последовательных вычислениях

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

И, кроме этого выполнять дополнительные действия(проверять, удачно ли завершились вызовы)

Page 23: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Какую бы еще монаду определить?

Что бы еще сделать дополнительное при последовательных вычислениях?

Считать деньги за функции («тридевятое царство»)

f x = do

y <- sin39 x

z <- exp39 x

return (y+z)

Подсчет суммы денег будет делать за нас >>=

23

Page 24: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Про д.з.:

пока опишем ‘почти монаду’

Опишем ‘почти монаду’

>>>= вместо >>=

return1 вместо return

f x =

sin39 x >>>= \y ->

exp39 x >>>= \z ->

return1 (y+z)

Просто чтобы нас не отвлекали всякие заклинания про классы, instance и т.д.

А совсем монады в следующий раз

24

Page 25: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Continuations

25

Page 26: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

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

Что делать, если не нашли

Page 27: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Еще пример

Найти первое число, большее 1000, а если его нет, то первое число большее 500, а если и его нет, то первое число большее 100 (а если и его нет, вернуть 0):

find (>1000) xs

(

find (>500) xs

(

find (>100) xs 0

)

)

27

Page 28: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

На листочке

28

Page 29: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

Как вернуть позицию в списке?

Сейчас будем считать, что наш find всегда что-то находить. Но остается другая проблема:

Когда мы ищем что-то в списке, хотелось бы вернуть не просто значение, а еще как-то и то место, на котором мы его нашли.

Например, хотелось бы написать find, чтобы его можно было вызвать три раза и найти третий элемент в списке, удовлетворяющий данному условию

Какой должен быть интерфейс у такого find?

Распостраненный вариант: возвращать пару (значение, еще не просмотренный хвост списка)

29

Page 30: План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает только 1, 3, 9, 27 … Как добавить? merge! ham = merge (map (*2)

На листочке

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