План на сегодняmsimuni.wdfiles.com/local--files/fp3/func11.pdf · Не хватает...

Preview:

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

Recommended