Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция ФилП.docx
Скачиваний:
10
Добавлен:
19.09.2019
Размер:
401.58 Кб
Скачать

Функции высших порядков

Когда мы рассматривали базовый язык функции явл объектами первого класса, с ними можно выполнять операции. В этой главе мы рассмотрим такого рода функции.

Функции, которые получают аргументы или дают результаты функции, называются функциями высших порядков.

В функц программе таких функций большинство.

add = \x->\y->x+y

Функции высших порядков позв определять целое семейство функций.

inc = add 1

dec = add (-1)

id = add 0

Функции высших порядков позв программировать на высоком уровне абстракции.

Сходство функций

Можно найти классы функций в которых много общего

Суммирует эелементы списка :

Sum [] = 0

Sum (x:xs) = x + sum xs

// prod перемножает

Prod [] = 1

Prod (x:xs) = x*prod xs

// and строит конъюнкцию всех элементов списка

And [] = True

And (x:xs) = X && and xs

Эти функции можно обобщить.

Обнаруживается общая схема рекурсии.

Каждой функции задается некоторое начальное значение.

0, 1, и True. Это отличительный признак.

Далее эти функции отличаются выполняемой операцией. + * &&

Если эти нач компоненты обозначить переменной, то мы получим более абстрактную функцию.

fold op init [] = init

fold op init (x:xs) = X `op` fold op init xs

ф-ия op и нач значение init от шага к шагу не меняется, но тем не менее передаются.

Или более компактно (эффективно)

fold op init ys = h ys

where

h [] = init

h (x:xs) = X `op` h xs

Функция полиморфна. Её тип

fold:: (a->b->b)->b->[a]->b

Функций fold для полноты нужно две, мы можем операцию взять левоассоциативную и правоассоциативную.

Foldr op init (x1 : x2 : … xn : [])

  • X1 `op` (x2 `op` (…(xn `op` init)…))

Операции прим справа налево

Foldl op init (x1 : x2 : … xn : [])

  • (…((init `op` x1) `op` x2)…) `op`xn

Если операция оп ассоциативна то можно брать любую из 2х функций.

Иногда правильный выбор между foldr и foldl может повысить эффективность. Сцепление списков выполним…

Foldr (++) [] [x,y,z] -> x ++ (y ++ z)

Foldl (++) [] [x,y,z] -> (x ++ y) ++ z

Рассмотрим пример где можно применить fold. Для реверсирования списков.

Reverse [] = []

Reberse (x:xs) = reverse xs ++ [x]

Лучше исп накапливающий параметр:

reverse xs = rev [] xs

where rev acc [] = acc

rev acc (x:xs) = rev (x:acc) xs

локальная ф rev – если исчерпался то результат то что накоплено в акк. Если список имеет голову и хвост то мы реверсируем хвост а голову окунаем в аккумулятор.

Rev напоминает наши предыдущие функции. Можно обратиться к асбтрактной фукнции…

Очень похоже на Foldl.

reverse xs = foldl revOp [] xs

where revOp a b = b : a

вместо revOp(она на один случай) мы можем написать:

(\ a b -> b : a)

Отображение списков

map _ [] = []

map f (x:xs) = f x : map f xs

map f xs = map’ xs

where

map’ [] = []

map’ (x:xs) = f x : map’ xs

ф f не меняется, лучше исп локальную функцию.

Example:

map(+1) [1,2,3] => [2,3,4]

Декартово произведение множеств

Список всех рядов

для каждого х из xs построить пару. берем y ….

cartProd :: [a] -> [b] ->[(a,b)]

cartProd xs ys = foldr (++) []

(map

Ряд для каждого x из xs

(\x -> (map (\y->(x,y)) ys))

xs)

Список должен быть плоским ( foldr (++) ).