Skip to content

Functional Programming

Функціональне програмування

Що таке функціональне програмування

Функціональне програмування - це галузь дискретної математики та парадигма програмування, в якій процес обчислення трактується як обчислення значень функцій в математичному розумінні останніх (на відміну від функцій як підпрограм у процедурному програмуванні).

Воно протиставляється імперативній парадигмі програмування, яка описує процес обчислень як послідовну зміну станів (значень, подібних до таких у теорії автоматів).

Links

Підтримка функціонального програмування в Python

Python частково підтримує парадигму функціонального програмування та дозволяє писати код у функціональному стилі. Крім того, в ньому присутні певні можливості, характерні для функціональних мов або вперше з'явилися у функціональних мовах (списковий вираз, лямбда-функції, функції вищого порядку і т.д.).

Що таке об'єкт першого класу

Об'єктами першого класу (first-class object, first-class entity, first-class citizen) у контексті певної мови програмування називаються сутності, які можуть бути передані як параметр, повернуті з функції або присвоєні змінній.

Об'єкт називають "об'єктом першого класу", якщо він:

  • може бути збережений у змінній або структурах даних;
  • може бути переданий в функцію як аргумент;
  • може бути повернутий з функції як результат;
  • може бути створений під час виконання програми;
  • внутрішньо самоідентифікується (незалежно від іменування).

Термін "об'єкт" використовується тут в загальному сенсі і не обмежується об'єктами мови програмування. У Python, так само як і в функціональних мовах, функції є об'єктами першого класу.

Що таке функція вищого порядку?

Функція вищого порядку - це функція, яка приймає інші функції як аргументи або повертає іншу функцію як результат. Основна ідея полягає в тому, що функції мають такий же статус, як і інші об'єкти даних. Це є важливим концептом у функціональному програмуванні.

Python має кілька вбудованих функцій вищого порядку, таких як map(), filter() і reduce().

  • map() - застосовує задану функцію до кожного елемента об'єкта, що ітерується, і повертає ітератор з результатами.
  • filter() - застосовує задану функцію до кожного елемента об'єкта, що ітерується, і повертає ітератор з елементами, для яких функція повернула True.
  • reduce() - поєднує елементи об'єкта, що ітерується, в одне значення, використовуючи задану функцію.

Що таке каррірування

Каррірування - це перетворення функції з багатьма аргументами на набір функцій, кожна з яких є функцією від одного аргумента. Ми можемо передати частину аргументів до функції і отримати назад функцію, яка очікує інші аргументи. Це перетворення було запропоновано М.Шейнфінкелем і Г.Фреге і отримало свою назву на честь Х.Каррі.

Створимо просту функцію greet, яка приймає привітання та ім'я як аргументи:

def greet(greeting, name):
    print(greeting + ', ' + name)

greet('Hello', 'German')

Невелике поліпшення дозволить створити нову функцію для будь-якого типу привітання і передати цій новій функції ім'я:

def greet_curried(greeting):
    def greet(name):
        print(greeting + ', ' + name)
    return greet

greet_hello = greet_curried('Hello')

greet_hello('German')
greet_hello('Ivan')

Або безпосередньо greet_curried. Подальша розробка можлива з будь-якою кількістю аргументів.

greet_curried('Hi')('Roma')

def greet_deeply_curried(greeting):
    def w_separator(separator):
        def w_emphasis(emphasis):
            def w_name(name):
                print(greeting + separator + name + emphasis)
            return w_name
        return w_emphasis
    return w_separator

greet = greet_deeply_curried("Hello")("...")(".")
greet('German')
greet('Ivan')

Опишіть функції map, reduce, filter модуля functools

Функція map застосовує функцію до кожного елемента послідовності.

Функція filter залишає тільки ті елементи послідовності, для яких задана функція є істинною.

Для Python більш канонічним є використання спискових виразів замість map-filter.

Функція reduce приймає функцію з двома аргументами, послідовність і опціональне початкове значення і обчислює скорочення (складання) послідовності як результат послідовного застосування даної функції до поточного значення (так званого аккумулятора) і наступного елемента послідовності.

Чим функціональне програмування відрізняється від ООП?

Summary

ООП моделює світ через об'єкти, що поєднують стан і поведінку, і змінюють свій стан. ФП будується на чистих функціях без побічних ефектів і незмінних даних - програма це композиція функцій, а не взаємодія об'єктів.

Об'єктно-орієнтоване програмування (ООП)

ООП моделює сутності з реального світу, об'єднуючи дані і поведінку всередині класу. Ключові принципи:

  • Інкапсуляція - об'єднання даних і методів усередині об'єкта.
  • Наслідування - клас може успадковувати поведінку іншого.
  • Поліморфізм - об'єкти різних типів використовуються однаково через спільний інтерфейс.

Стан об'єкта може змінюватися. Програміст створює класи, що описують сутності, і взаємодіє з ними через методи.

Функціональне програмування (ФП)

ФП будується на чистих функціях: функція не залежить від зовнішнього стану і завжди повертає однаковий результат на однаковий вхід. Принципи:

  • Іммутабельність - дані не змінюються; натомість створюються нові копії.
  • Чисті функції - без побічних ефектів (не міняють глобальні змінні, не пишуть у файл).
  • Композиція функцій - програма складається з викликів функцій і їх композиції, а не з взаємодій об'єктів.
  • Декларативність - описуємо що треба, а не як обчислити.

Приклад: середній бал студента

ООП-підхід:

class Student:
    def __init__(self, grades):
        self.grades = grades

    def average(self):
        return sum(self.grades) / len(self.grades)

s = Student([4, 5, 3, 5])
s.average()  # 4.25

Функціональний підхід:

from statistics import mean

grades = [4, 5, 3, 5]
mean(grades)  # 4.25 - no class, no mutable state

Застосування

  • ООП добре лягає на системи з багатьма сутностями і складною ієрархією - веб-застосунки з бізнес-логікою, домен з купою агрегатів, ігри.
  • ФП ефективне в обчисленнях, обробці даних, паралельних задачах, у потоках подій - там, де важливі надійність, передбачуваність і відсутність прихованого стану.

Python - мультипарадигмова мова: можна (і часто варто) поєднувати обидва підходи в одному проєкті.