Функциональное программирование на Яве DevClub 26.11.2009 Andrei Solntsev
О чём это мы? Данный пптах даёт представление о методах Функционального Программирования и их применении в ООП-языках типа Java Кое-где придётся подумать!
Оглавление ФП для чайников Основные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
Введение в ФП Вычисление - последовательное выполнение команд, изменяющих состояние . Императивное программирование Функциональное программирование Вычисление - нахождение значения выражения КАК Выражения образованы из функций для комбинации базовых значений и других функций Программа состоит из нескольких последовательных команд . ЧТО против
Алгоритм На каком примере всем объясняют понятие «алгоритм»? Бутерброд!
Алгоритм бутерброда Фунцкия createSandwich Возьми кусок хлеба Намажь масло на хлеб Положи сыр на масло return result Императивный стиль return Функциональный стиль положи ( сыр , намажь ( масло , хлеб ) )
Алгоритм бутерброда Что , если мы хотим использовать колбасу вместо сыра ? Давайте передавать колбасу/сыр как входной параметр функции Нет проблем !
Алгоритм бутерброда Возьми низ Намажь середину на низ Положи верх на середину return result Function createSandwich ( низ , середина , верх ) return положи ( верх , намажь ( середина , низ ) ) Function createSandwich ( низ , середина , верх ) Нет проблем ! хлеб масло колбаса
Алгоритм бутерброда Что , если мы хотим не намазывать масло, а класть кусками? Императивное программирование : Проблема ! Функциональное программирование : по-прежнему нет проблем
Алгоритм бутерброда Возьми низ if способ = ‘ класть ’ положи середину на низ else намажь середину на низ end if Положи верх на середину return result Function createSandwich ( низ , середина , верх , способ ) хлеб масло колбаса класть Альтернативный вариант : создать 2 разные функции  Дублирование кода Императивное программирование : Проблема ! Больше способов – больше IF’ ов
Алгоритм бутерброда return put ( верх , action ( середина, низ ) ) Function createSandwich ( низ , середина , верх , action ) хлеб масло колбаса класть Action – это функция с двумя аргументами Намазывать класть … createSandwich – функция более высокого порядка ( higher-order function ), которая принимает другую функцию как аргумент Функциональное программирование : нет проблем
Функциональный бутерброд
Основные свойства ФП Что такое Функциональное Программмирование ? Closures and higher order functions Lazy evaluation Recursion as a mechanism for control flow Enforcement of referential transparency No side-effects Lambda calculus Функциональные языки Lisp (AutoCad) Haskell, Scheme, Logo XSLT Там, где традиционная императивная программа использует цикл для прохождения по списку, функциональный стиль использует функцию высокого порядка map, которая принимает другую функцию и список, применяет эту функцию к каждому элементу списка и возвращает список из результатов. Scala, LambdaJ, Clojure
ФП для чайников Основные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
Примеры кода на Haskell a dd :: I n teger -> Integer -> Integer add  x y =  x + y functions add  1   2 =   3 add  6   9 =   1 5 add  1 =   ? Ух ты ! add  1 = функция типа Integer -> Integer Currying http://en.wikipedia.org/wiki/Currying
Примеры кода на Haskell a dd :: I n teger -> Integer -> Integer add  x y =  x + y 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
ones = 1 : ones Примеры кода на Haskell Бесконечные структуры данных numsFrom n = n : numsFrom (n+1) squares = map (^2) (numsfrom 0) take 5 squares => [0,1,4,9,16] Это выражение вычисляется за конечное число шагов Потому что Lazy Evaluation!
Примеры кода в стиле ФП в Java java.util.Properties Properties properties = new Properties(); properties.setProperty(“firstName", groom.getFirstName()); properties.setProperty(“lastName", groom.getLastName()); properties.setProperty(“salary", groom.getSalary()); return parameters; return Императивный Функциональный return new Properties() .setProperty(“firstName", groom.getFirstName()) .setProperty(“lastName", groom.getLastName()) .setProperty(“salary", groom.getSalary()); Плюсы? Минусы? йа баго нихт баго
Примеры кода в стиле ФП в 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(); Императивный Функциональный Плюсы? Минусы ?
ФП : За и против За Надёжный ( reliable ) код Читаемый (readable) код Многократно используемый ( Reusable ) код Неестественный для человека Неестественный для компьютера Отсутствие контроля над процессом Производительность Против Пример : алгоритм быстрой сортировки ( Quick Sort )
Quicksort на языке Haskell qsort [] = [] qsort (x:xs) = qsort elts_lt_x ++ [x] ++ qsort elts_greq_x where elts_lt_x = [y | y <- xs, y < x] elts_greq_x = [y | y <- xs, y >= x] Сравните с Quicksort на языке C:
Quicksort на языке C qsort( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }
ФП : За и против В языках типа Java, ФП хорошо подходит для реализации бизнес-логики и обработки списков Проще придумывать, писать и поддерживать ПО, но программист имеет меньше контроля над тем, что происходит во время выполнения программы. За Вывод
ФП для чайников Основные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
25 ый кадр 25 ый кадр
Бизнес-логика с помощью ФП Класс 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 , то возраст проверять не нужно Отфильтровывает женихов Как сделать более сложные проверки?
Бизнес-логика с помощью ФП Класс GroomFilter List suitableGrooms = new ArrayList(); for (groom in allGrooms) { if ( groomChecker .apply(groom)) suitableGrooms.add(groom); } return suitableGrooms; List filterGrooms(List allGrooms, Predicate groomChecker ) Передаём функцию как параметр
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/
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); … }
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 ) }
Бизнес-логика с помощью ФП Класс GroomFilter return Collections2.filter (allGrooms, groomChecker); List filterGrooms(List allGrooms, Predicate groomChecker ) Функция filterGrooms становится ещё проще
Бизнес-логика с помощью ФП Клиент 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
Применение ФП : Фильтры Дано : список имён женихов . Найти : все имена, начинающиеся на “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 ; Императивное программирование:
Применение ФП : Фильтры Функциональное программирование: import com.google.common.collect.Collections2; return Collections2 . filter( allGrooms, StringPredicates.startsWith( “Mr.” ) ) ; Дано : список имён женихов . Найти : все имена, начинающиеся на “Mr.”
Применение ФП : Функции Дано : список женихов Найти : список имён женихов List groomsNames = new ArrayList(); for (Iterator it = allGrooms .iterator(); it.hasNext(); ) { Groom groom = (Groom) it.next(); groomsNames .add(groom.getName()); } return groomsNames ; Императивное программирование
Применение ФП : Функции import com.google.common.collect.Collections2; return Collections2. transform( allGrooms , new Function<Groom, String> () { public String apply(Groom groom) { return groom.getName(); } } ) ; Функциональное программирование Дано : список женихов Найти : список имён женихов На первый взгляд, не столь красиво, но может быть вынесено в отдельный класс и многократно использовано!
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);
Эпи log 4 j В следующий раз, прежде чем написать FOR или IF, задумайтесь! Скачайте себе Haskell и поиграйтесь на досуге. Если это не убьёт ваш мозг, то сделает его сильнее.

Functional Programming Dev Club 2009 - final

  • 1.
  • 2.
    О чём этомы? Данный пптах даёт представление о методах Функционального Программирования и их применении в ООП-языках типа Java Кое-где придётся подумать!
  • 3.
    Оглавление ФП длячайников Основные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
  • 4.
    Введение в ФПВычисление - последовательное выполнение команд, изменяющих состояние . Императивное программирование Функциональное программирование Вычисление - нахождение значения выражения КАК Выражения образованы из функций для комбинации базовых значений и других функций Программа состоит из нескольких последовательных команд . ЧТО против
  • 5.
    Алгоритм На какомпримере всем объясняют понятие «алгоритм»? Бутерброд!
  • 6.
    Алгоритм бутерброда Фунцкия createSandwich Возьми кусок хлеба Намажь масло на хлеб Положи сыр на масло return result Императивный стиль return Функциональный стиль положи ( сыр , намажь ( масло , хлеб ) )
  • 7.
    Алгоритм бутерброда Что, если мы хотим использовать колбасу вместо сыра ? Давайте передавать колбасу/сыр как входной параметр функции Нет проблем !
  • 8.
    Алгоритм бутерброда Возьми низ Намажь середину на низ Положи верх на середину return result Function createSandwich ( низ , середина , верх ) return положи ( верх , намажь ( середина , низ ) ) Function createSandwich ( низ , середина , верх ) Нет проблем ! хлеб масло колбаса
  • 9.
    Алгоритм бутерброда Что, если мы хотим не намазывать масло, а класть кусками? Императивное программирование : Проблема ! Функциональное программирование : по-прежнему нет проблем
  • 10.
    Алгоритм бутерброда Возьми низ if способ = ‘ класть ’ положи середину на низ else намажь середину на низ end if Положи верх на середину return result Function createSandwich ( низ , середина , верх , способ ) хлеб масло колбаса класть Альтернативный вариант : создать 2 разные функции  Дублирование кода Императивное программирование : Проблема ! Больше способов – больше IF’ ов
  • 11.
    Алгоритм бутерброда returnput ( верх , action ( середина, низ ) ) Function createSandwich ( низ , середина , верх , action ) хлеб масло колбаса класть Action – это функция с двумя аргументами Намазывать класть … createSandwich – функция более высокого порядка ( higher-order function ), которая принимает другую функцию как аргумент Функциональное программирование : нет проблем
  • 12.
  • 13.
    Основные свойства ФПЧто такое Функциональное Программмирование ? Closures and higher order functions Lazy evaluation Recursion as a mechanism for control flow Enforcement of referential transparency No side-effects Lambda calculus Функциональные языки Lisp (AutoCad) Haskell, Scheme, Logo XSLT Там, где традиционная императивная программа использует цикл для прохождения по списку, функциональный стиль использует функцию высокого порядка map, которая принимает другую функцию и список, применяет эту функцию к каждому элементу списка и возвращает список из результатов. Scala, LambdaJ, Clojure
  • 14.
    ФП для чайниковОсновные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
  • 15.
    Примеры кода на Haskell a dd :: I n teger -> Integer -> Integer add  x y =  x + y functions add  1   2 =   3 add  6   9 =   1 5 add  1 =   ? Ух ты ! add  1 = функция типа Integer -> Integer Currying http://en.wikipedia.org/wiki/Currying
  • 16.
    Примеры кода на Haskell a dd :: I n teger -> Integer -> Integer add  x y =  x + y 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.
    ones = 1 : ones Примеры кода на Haskell Бесконечные структуры данных numsFrom n = n : numsFrom (n+1) squares = map (^2) (numsfrom 0) take 5 squares => [0,1,4,9,16] Это выражение вычисляется за конечное число шагов Потому что Lazy Evaluation!
  • 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()); Плюсы? Минусы? йа баго нихт баго
  • 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(); Императивный Функциональный Плюсы? Минусы ?
  • 20.
    ФП : За и против За Надёжный ( reliable ) код Читаемый (readable) код Многократно используемый ( Reusable ) код Неестественный для человека Неестественный для компьютера Отсутствие контроля над процессом Производительность Против Пример : алгоритм быстрой сортировки ( Quick Sort )
  • 21.
    Quicksort на языкеHaskell qsort [] = [] qsort (x:xs) = qsort elts_lt_x ++ [x] ++ qsort elts_greq_x where elts_lt_x = [y | y <- xs, y < x] elts_greq_x = [y | y <- xs, y >= x] Сравните с Quicksort на языке C:
  • 22.
    Quicksort на языкеC qsort( a, lo, hi ) int a[], hi, lo; { int h, l, p, t; if (lo < hi) { l = lo; h = hi; p = a[hi]; do { while ((l < h) && (a[l] <= p)) l = l+1; while ((h > l) && (a[h] >= p)) h = h-1; if (l < h) { t = a[l]; a[l] = a[h]; a[h] = t; } } while (l < h); t = a[l]; a[l] = a[hi]; a[hi] = t; qsort( a, lo, l-1 ); qsort( a, l+1, hi ); } }
  • 23.
    ФП : За и против В языках типа Java, ФП хорошо подходит для реализации бизнес-логики и обработки списков Проще придумывать, писать и поддерживать ПО, но программист имеет меньше контроля над тем, что происходит во время выполнения программы. За Вывод
  • 24.
    ФП для чайниковОсновные свойства ФП Примеры кода на Haskell Примеры кода на Java ФП для бизнес-логики
  • 25.
    25 ый кадр 25 ый кадр
  • 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.
    Бизнес-логика с помощьюФП Класс 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.
    Google collections packagecom.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.
    Google collections packagecom.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.
    Google collections packagecom.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.
    Бизнес-логика с помощьюФП Класс GroomFilter return Collections2.filter (allGrooms, groomChecker); List filterGrooms(List allGrooms, Predicate groomChecker ) Функция filterGrooms становится ещё проще
  • 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.
    Применение ФП : Фильтры Дано : список имён женихов . Найти : все имена, начинающиеся на “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.
    Применение ФП : Фильтры Функциональное программирование: import com.google.common.collect.Collections2; return Collections2 . filter( allGrooms, StringPredicates.startsWith( “Mr.” ) ) ; Дано : список имён женихов . Найти : все имена, начинающиеся на “Mr.”
  • 35.
    Применение ФП : Функции Дано : список женихов Найти : список имён женихов List groomsNames = new ArrayList(); for (Iterator it = allGrooms .iterator(); it.hasNext(); ) { Groom groom = (Groom) it.next(); groomsNames .add(groom.getName()); } return groomsNames ; Императивное программирование
  • 36.
    Применение ФП : Функции import com.google.common.collect.Collections2; return Collections2. transform( allGrooms , new Function<Groom, String> () { public String apply(Groom groom) { return groom.getName(); } } ) ; Функциональное программирование Дано : список женихов Найти : список имён женихов На первый взгляд, не столь красиво, но может быть вынесено в отдельный класс и многократно использовано!
  • 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.
    Эпи log 4j В следующий раз, прежде чем написать FOR или IF, задумайтесь! Скачайте себе Haskell и поиграйтесь на досуге. Если это не убьёт ваш мозг, то сделает его сильнее.