Functional Programming Dev Club 2009 - final

1,348 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,348
On SlideShare
0
From Embeds
0
Number of Embeds
280
Actions
Shares
0
Downloads
16
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Functional Programming Dev Club 2009 - final

  1. 1. Функциональное программирование на Яве DevClub 26.11.2009 Andrei Solntsev
  2. 2. О чём это мы? Данный пптах даёт представление о методах Функционального Программирования и их применении в ООП-языках типа Java Кое-где придётся подумать!
  3. 3. Оглавление <ul><li>ФП для чайников </li></ul><ul><li>Основные свойства ФП </li></ul><ul><li>Примеры кода на Haskell </li></ul><ul><li>Примеры кода на Java </li></ul><ul><li>ФП для бизнес-логики </li></ul>
  4. 4. Введение в ФП Вычисление - последовательное выполнение команд, изменяющих состояние . Императивное программирование Функциональное программирование Вычисление - нахождение значения выражения КАК Выражения образованы из функций для комбинации базовых значений и других функций Программа состоит из нескольких последовательных команд . ЧТО против
  5. 5. Алгоритм На каком примере всем объясняют понятие «алгоритм»? Бутерброд!
  6. 6. Алгоритм бутерброда Фунцкия createSandwich <ul><li>Возьми кусок хлеба </li></ul><ul><li>Намажь масло на хлеб </li></ul><ul><li>Положи сыр на масло </li></ul><ul><li>return result </li></ul>Императивный стиль return Функциональный стиль положи ( сыр , намажь ( масло , хлеб ) )
  7. 7. Алгоритм бутерброда Что , если мы хотим использовать колбасу вместо сыра ? Давайте передавать колбасу/сыр как входной параметр функции Нет проблем !
  8. 8. Алгоритм бутерброда <ul><li>Возьми низ </li></ul><ul><li>Намажь середину на низ </li></ul><ul><li>Положи верх на середину </li></ul><ul><li>return result </li></ul>Function createSandwich ( низ , середина , верх ) return положи ( верх , намажь ( середина , низ ) ) Function createSandwich ( низ , середина , верх ) Нет проблем ! хлеб масло колбаса
  9. 9. Алгоритм бутерброда Что , если мы хотим не намазывать масло, а класть кусками? Императивное программирование : Проблема ! Функциональное программирование : по-прежнему нет проблем
  10. 10. Алгоритм бутерброда <ul><li>Возьми низ </li></ul><ul><li>if способ = ‘ класть ’ положи середину на низ else намажь середину на низ end if </li></ul><ul><li>Положи верх на середину </li></ul><ul><li>return result </li></ul>Function createSandwich ( низ , середина , верх , способ ) хлеб масло колбаса класть Альтернативный вариант : создать 2 разные функции  Дублирование кода Императивное программирование : Проблема ! Больше способов – больше IF’ ов
  11. 11. Алгоритм бутерброда return put ( верх , action ( середина, низ ) ) Function createSandwich ( низ , середина , верх , action ) хлеб масло колбаса класть Action – это функция с двумя аргументами <ul><li>Намазывать </li></ul><ul><li>класть </li></ul><ul><li>… </li></ul>createSandwich – функция более высокого порядка ( higher-order function ), которая принимает другую функцию как аргумент Функциональное программирование : нет проблем
  12. 12. Функциональный бутерброд
  13. 13. Основные свойства ФП Что такое Функциональное Программмирование ? <ul><li>Closures and higher order functions </li></ul><ul><li>Lazy evaluation </li></ul><ul><li>Recursion as a mechanism for control flow </li></ul><ul><li>Enforcement of referential transparency </li></ul><ul><li>No side-effects </li></ul><ul><li>Lambda calculus </li></ul>Функциональные языки <ul><li>Lisp (AutoCad) </li></ul><ul><li>Haskell, Scheme, Logo </li></ul><ul><li>XSLT </li></ul>Там, где традиционная императивная программа использует цикл для прохождения по списку, функциональный стиль использует функцию высокого порядка map, которая принимает другую функцию и список, применяет эту функцию к каждому элементу списка и возвращает список из результатов. <ul><li>Scala, LambdaJ, Clojure </li></ul>
  14. 14. <ul><li>ФП для чайников </li></ul><ul><li>Основные свойства ФП </li></ul><ul><li>Примеры кода на Haskell </li></ul><ul><li>Примеры кода на Java </li></ul><ul><li>ФП для бизнес-логики </li></ul>
  15. 15. Примеры кода на Haskell <ul><li>a dd :: I n teger -> Integer -> Integer </li></ul><ul><li>add  x y =  x + y </li></ul>functions add  1   2 =   3 add  6   9 =   1 5 add  1 =   ? Ух ты ! add  1 = функция типа Integer -> Integer Currying http://en.wikipedia.org/wiki/Currying
  16. 16. Примеры кода на Haskell <ul><li>a dd :: I n teger -> Integer -> Integer </li></ul><ul><li>add  x y =  x + y </li></ul>functions inc :: Integer -> Integer inc = add 1 map :: (a->b) -> [a] -> [b] map  f  []       =  [] map  f (x:xs)    =  f x : map f xs Uncurried function F unction can be returned as a value ! Higher-order function curried function
  17. 17. <ul><li>ones = 1 : ones </li></ul>Примеры кода на Haskell Бесконечные структуры данных numsFrom n = n : numsFrom (n+1) squares = map (^2) (numsfrom 0) take 5 squares => [0,1,4,9,16] Это выражение вычисляется за конечное число шагов Потому что Lazy Evaluation!
  18. 18. Примеры кода в стиле ФП в Java java.util.Properties Properties properties = new Properties(); properties.setProperty(“firstName&quot;, groom.getFirstName()); properties.setProperty(“lastName&quot;, groom.getLastName()); properties.setProperty(“salary&quot;, groom.getSalary()); return parameters; return Императивный Функциональный return new Properties() .setProperty(“firstName&quot;, groom.getFirstName()) .setProperty(“lastName&quot;, groom.getLastName()) .setProperty(“salary&quot;, groom.getSalary()); <ul><li>Плюсы? </li></ul><ul><li>Минусы? </li></ul>йа баго нихт баго
  19. 19. Примеры кода в стиле ФП в Java java.lang.StringBuffer StringBuffer sb = new StringBuffer(); sb.append(“a”); sb.append(“b”); sb.append(“c”); return sb.toString(); return new StringBuffer() .append(“a”); .append(“b”); .append(“c”) .toString(); Императивный Функциональный <ul><li>Плюсы? </li></ul><ul><li>Минусы ? </li></ul>
  20. 20. ФП : За и против За <ul><li>Надёжный ( reliable ) код </li></ul><ul><li>Читаемый (readable) код </li></ul><ul><li>Многократно используемый ( Reusable ) код </li></ul><ul><li>Неестественный для человека </li></ul><ul><li>Неестественный для компьютера </li></ul><ul><li>Отсутствие контроля над процессом </li></ul><ul><li>Производительность </li></ul>Против Пример : алгоритм быстрой сортировки ( Quick Sort )
  21. 21. Quicksort на языке Haskell <ul><li>qsort [] = [] </li></ul><ul><li>qsort (x:xs) = qsort elts_lt_x ++ </li></ul><ul><li>[x] ++ </li></ul><ul><li>qsort elts_greq_x </li></ul><ul><li>where </li></ul><ul><li>elts_lt_x = [y | y <- xs, y < x] </li></ul><ul><li>elts_greq_x = [y | y <- xs, y >= x] </li></ul>Сравните с Quicksort на языке C:
  22. 22. Quicksort на языке C <ul><li>qsort( a, lo, hi ) int a[], hi, lo; </li></ul><ul><li>{ </li></ul><ul><li>int h, l, p, t; </li></ul><ul><li>if (lo < hi) { </li></ul><ul><li>l = lo; h = hi; p = a[hi]; </li></ul><ul><li>do { </li></ul><ul><li>while ((l < h) && (a[l] <= p)) </li></ul><ul><li>l = l+1; </li></ul><ul><li>while ((h > l) && (a[h] >= p)) </li></ul><ul><li>h = h-1; </li></ul><ul><li>if (l < h) { </li></ul><ul><li>t = a[l]; a[l] = a[h]; a[h] = t; </li></ul><ul><li>} </li></ul><ul><li>} while (l < h); </li></ul><ul><li>t = a[l]; a[l] = a[hi]; a[hi] = t; </li></ul><ul><li>qsort( a, lo, l-1 ); </li></ul><ul><li>qsort( a, l+1, hi ); </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  23. 23. ФП : За и против В языках типа Java, ФП хорошо подходит для реализации бизнес-логики и обработки списков Проще придумывать, писать и поддерживать ПО, но программист имеет меньше контроля над тем, что происходит во время выполнения программы. За Вывод
  24. 24. <ul><li>ФП для чайников </li></ul><ul><li>Основные свойства ФП </li></ul><ul><li>Примеры кода на Haskell </li></ul><ul><li>Примеры кода на Java </li></ul><ul><li>ФП для бизнес-логики </li></ul>
  25. 25. 25 ый кадр 25 ый кадр
  26. 26. Бизнес-логика с помощью ФП Класс GroomFilter List suitableGrooms = new ArrayList(); for (groom in allGrooms) { if ( minAge > -1 && groom.getAge() < minAge ) continue; if (maxAge > -1 && groom.getAge() > maxAge) continue; suitableGrooms .add(groom); } return suitableGrooms ; List filterGrooms(List allGrooms , int minAge, int maxAge) Если age = -1 , то возраст проверять не нужно Отфильтровывает женихов Как сделать более сложные проверки?
  27. 27. Бизнес-логика с помощью ФП Класс GroomFilter List suitableGrooms = new ArrayList(); for (groom in allGrooms) { if ( groomChecker .apply(groom)) suitableGrooms.add(groom); } return suitableGrooms; List filterGrooms(List allGrooms, Predicate groomChecker ) Передаём функцию как параметр
  28. 28. Google collections package com.google.common.base; public interface Predicate <T> { { /** * Возвращает true или false для данного объекта */ boolean apply (T input); } http://bwinterberg.blogspot.com/2009/09/introduction-to-google-collections.html http://code.google.com/p/google-collections/
  29. 29. Google collections package com.google.common.base; public class Predicates { static <T> Predicate<T> alwaysTrue (); static <T> Predicate<T> alwaysFalse (); static <T> Predicate<T> isNull () ; static <T> Predicate<T> notNull (); static <T> Predicate<T> not (Predicate<T> predicate); static <T> Predicate<T> and (Predicate<? super T>... components); … }
  30. 30. Google collections package com.google.common.collect; public class Collections2 { static <E> Collection<E> filter ( Collection<E> unfiltered , Predicate<? super E> predicate ) static <F, T> Collection<T> transform ( Collection<F> fromCollection , Function<? super F, T> function ) }
  31. 31. Бизнес-логика с помощью ФП Класс GroomFilter return Collections2.filter (allGrooms, groomChecker); List filterGrooms(List allGrooms, Predicate groomChecker ) Функция filterGrooms становится ещё проще
  32. 32. Бизнес-логика с помощью ФП Клиент 1 List suitableGrooms grooms = GroomFilter.filterGrooms(…, new Predicate<Groom>() { public boolean apply(Groom groom) { return groom.getAge() > 23; } } ); Клиент 2 List suitableGrooms = GroomFilter.filterGrooms(…, Predicates.alwaysTrue() ); Closure – Объект, представляющий функцию Анонимные классы часто используются в качестве closures
  33. 33. Применение ФП : Фильтры Дано : список имён женихов . Найти : все имена, начинающиеся на “Mr.” List gentlemen = new LinkedList(); for (Iterator it = groomsNames .iterator(); it.hasNext(); ) { String name = (String) it.next(); if (name != null && name.startsWith(“Mr.”)) { gentlemen .add(name); } } return gentlemen ; Императивное программирование:
  34. 34. Применение ФП : Фильтры Функциональное программирование: import com.google.common.collect.Collections2; return Collections2 . filter( allGrooms, StringPredicates.startsWith( “Mr.” ) ) ; Дано : список имён женихов . Найти : все имена, начинающиеся на “Mr.”
  35. 35. Применение ФП : Функции Дано : список женихов Найти : список имён женихов List groomsNames = new ArrayList(); for (Iterator it = allGrooms .iterator(); it.hasNext(); ) { Groom groom = (Groom) it.next(); groomsNames .add(groom.getName()); } return groomsNames ; Императивное программирование
  36. 36. Применение ФП : Функции import com.google.common.collect.Collections2; return Collections2. transform( allGrooms , new Function<Groom, String> () { public String apply(Groom groom) { return groom.getName(); } } ) ; Функциональное программирование Дано : список женихов Найти : список имён женихов На первый взгляд, не столь красиво, но может быть вынесено в отдельный класс и многократно использовано!
  37. 37. Google collections GC позволяет сделать и более элегантные конструкции boolean result = and( not( in(list1) ), in(list2), in(list3)).apply(&quot;1&quot;); Collection names = Joiner.on(&quot;; &quot;).useForNull(&quot;B000&quot;).join(filtered);
  38. 38. Эпи log 4 j <ul><li>В следующий раз, прежде чем написать FOR или IF, задумайтесь! </li></ul>Скачайте себе Haskell и поиграйтесь на досуге. Если это не убьёт ваш мозг, то сделает его сильнее.

×