Skip to content

epogrebnyak/functional-programming-jargon

Repository files navigation

This is an abridged and modified Russian draft translation of Functional Programming Jargon with examples in Haskell. Some code examples borrowed from Turkish translation.

Эта статья - draft сокращенного перевода и переработки публикации Functional Programming Jargon с примерами на Нaskell, часть из которых взята из турецкой версии статьи. Перевод оригинальной статьи с примерами на JavaScript выполнен здесь.

Словарь сленга функционального программирования

У функционального программирования (ФП) есть много преимуществ, и как результат, его популярность растет. При этом у любой парадигмы программирования есть своя терминология и жаргон, и ФП - не исключение. С помощью этого словаря мы надеемся упростить задачу изучения ФП.

Содержание

1. Функции

Определение функции

Function

Функция f :: X -> Y каждому элементу x типа X сопоставляет элемент f x типа Y.

x называется аргументом функции, а f x - значением функции.

Функции, которые соответствуют данному определению, являются:

  • тотальными - каждому возможному аргументу сопоставлено значение функции,
  • детерминированными - каждому аргументу всегда соответствует одно и то же значение функции,
  • чистыми - вычисляют значение по аргументу и не производят никаких скрытых операций, приводящих к побочным эффектам.

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

Примечание: в программировании функцией может называться и та последовательность операций, которая приводит к побочным эффектам (записи на диск, проведению ввода-вывода, изменению глобальных переменных). Чтобы отличить их от функций в данном определении, такие операции можно называть процедурами.

Операции с фукциями

Композиция функций

Создание из двух функций f(x) и g(x) третьей функции h, результатом которой является применение функции f к g(x): h(x) = f(g(x)).

В Haskell композиция функций производится оператором . (точка). Такая запись в point-free форме более лаконична, чем запись с аргументом:

-- Предположим, у нас определены две функции  -- со следующими подписями even :: Int -> Bool not :: Bool -> Bool -- Давайте сдлаем новую функцию, которая проверяет  -- является ли значение нечетным myOdd :: Int -> Bool myOdd x = not (even x) -- ... или сделаем то же самое с использованием оператора . myOdd :: Int -> Bool myOdd = not . even

пример полностью

-- Функция desort создается путем комбинации  -- сортировки и перечисления списка в обратном порядке desort = reverse . sort

источник

Point-free стиль записи

Point-free style

Способ описать функцию без обозначения ее аргументов в явном виде.

Сравните:

sum = foldr (+) 0

и

sum' xs = foldr (+) 0 xs

Обе фукнции выполняют одно и то же действие суммирования, однако запись в point-free стиле считается более лаконичной и может содержать меньше ошибок.

Однако запись более сложных функций в point-free стиле может затруднять понимание логики вычислений.

Point-free стиль на русском также называется бесточечный стиль.

Ссылки

Лямбда-функция

Lambda

Функция без имени, анонимная фукнция.

\x -> x + 1

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

Prelude> map (\x -> x + 1) [1..4] [2,3,4,5]

Функция высшего порядка (ФВП)

Higher-Order Function (HOF)

Функция, которая принимает другую функцию как аргумент и/или возвращает функцию как результат.

Prelude> let add3 a = a + 3 Prelude> map add3 [1..4] [4,5,6,7]
Prelude> filter (<4) [1..10] [1,2,3]

Не совсем "правильные" функции

Частичная функция

Partial function

Частичная функция - это функция, для которой нарушается свойство тотальности. Частичная функция недоопределена: существуют значения аргумента, для которых частичная функция не может вычислить результат или не закончит свое исполнение.

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

Пример запроса несуществующего элемента списка:

[1,2,3] !! 5

Для устранения частичных функций могут применяться следующие приемы:

  • автоматическая проверка на частичные функции на уровне компилятора - в этом случае программа не будет запущена, выведется сообщение об ошибке;
  • добавить в область значений функции дополнительное значение, которое выдается функцией, когда аргумент не может быть обработан;
  • различные проверки допустимости исходных значений.

Подробнее см. например здесь.

Чистота и побочные эффекты

Чистота

Purity

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

Все функции в языке Haskell являются чистыми. Настолько чистыми, что для того, чтобы получить побочный эффект в виде записи на диск или вывода на экран надо еще очень постараться.

Побочные эффекты

Side effects

У функции или выражения есть побочный эффект помимо вычисления значения, если она взаимодействует (осуществляет чтение или запись) во внешние изменяемое состояние.

Таких фукнций на Haskell нет, примеры на JavaScript:

const differentEveryTime = new Date()
console.log('IO is a side effect!')

Аргументы функции и их обработка

Арность функции

Arity

Количество аргументов, которое принимает функция (унарная, бинарная и т.д.)

Prelude> let sum a b = a + b Prelude> :t sum sum :: Num a => a -> a -> a -- Арность функции sum равна 2 

Каррирование

Currying

Преобразование функции, которая принимает несколько аргументов, в функцию, которая принимает один аргумент и возвращает функцию, которая далее применяентся к последующим аргументам.

В отличие от других языков программирования функции многих аргументов в Haskell каррированы по умолчанию. Это значит, что частичное применение (см. ниже) доступно для всех функций многих аргументов и не требует специальных действий.

В примере ниже функция sum обрабатывает кортеж из двух значений (a, b). Функция curry преобразует функцию sum в curriedSum, которая последовательно принимает два аргумента a и b.

Prelude> let sum (a, b) = a + b Prelude> let curriedSum = curry sum Prelude> curriedSum 40 2 42

Ссылки

Частичное применение

Partial Application

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

Частичное применение позволяет из более общих или сложных функций получать более простые функции с необходимым специфическим поведением.

-- Создаем функцию сложения двух элементов Prelude> let add x y = x + y -- Создадим функцию для увеличения аргумента на единицу. -- Частично применим функцию add к значению 1. -- В результате получилась новая функция, -- которой мы присвоили имя inc Prelude> let inc = add 1 Prelude> inc 8 Prelude> 9 

Предупреждение. Частичное применение не следует путать с частичной функцией - это похожие названия, означающие разные вещи.

Ссылки

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

Прим. переводчика: термины, которые собраны в этом разделе, не показались мне фундаментальными или интересными. Здесь вы найдете их краткое определение, но заучивать или сильно вникать в них, на мой взгляд, не нужно.

Индемпотентность

Indepotent

Функция является идемпотентной, если ее повторное применение не влияет на исходный результат:

f(f(x)) ≍ f(x) 
Prelude> abs (abs (-1)) 1
Prelude Data.List> sort (sort [1,4,3,1,5]) [1,1,3,4,5]

Предикат

Predicate

Функция, возвращающая значение правда или ложь. Обычно используется для фильтрации последовательности значений по какому-либо признаку.

Prelude> let predThree a = a < 3 Prelude> filter predThree [1..10] [1,2]

Замыкание

Closure

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

Замыкание — это особый вид функции. Она определена в теле другой функции и создаётся каждый раз во время её выполнения. Синтаксически это выглядит как функция, находящаяся целиком в теле другой функции. При этом вложенная внутренняя функция содержит ссылки на локальные переменные внешней функции. Каждый раз при выполнении внешней функции происходит создание нового экземпляра внутренней функции, с новыми ссылками на переменные внешней функции.

Источник:

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

Поскольку Haskell основан на лямбда-исчислении (см.) замыкания используются в нем естественным образом и не являются чем-то особенным.

Вымученный пример замыкания на Haskell:

-- Переменная x не является аргументом лямбда-функции,  -- но доступна внутри тела функции f f x = (\y -> x + y) -- привычная запись на Haskell f x y = x + y

Примечание: функция-комбинатор, в отличие от замыкания, использует только переданные ей аргументы.

Аннотация типа

Type signatures

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

В Haskell подпись типа может задаваться напрямую в коде. Например, после определения inc :: Int -> Int компилятор будет ожидать, что под именем inc будет определена функция, которая принимает значение типа Int и выдает результат также типа Int. Если под именем inc будет определна функция с другим поведением, компилятор выдаст ошибку.

В отсутствие заданой подписи типа компилятор сам выводит ее наиболее общий вид:

Prelude> inc x = x + 1 Prelude> :t inc inc :: Num a => a -> a

inc :: Num a => a -> a - это подпись, выведенная компилятором. Она говорит о том, что имя inc - это функция, которая принимает значение некоторого типа а и выдает значение того же типа a, при этом сам тип а - принадлежит классу типов Num, который объединяет типы, выражающие числа.

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

2. Типы

Тип (данных)

Тип представляет собой набор возможных значений. Например, у типа Bool есть два значения True и False. Тип Int включает в себя все целочисленные значения.

Типы бывают простые и составные. Например, мы можем создать новый составной тип данных
Point объвив, что он состоит из двух значений типа Float.

data Point = Point Float Float

Термины тип и тип данных взаимозаменяемы.

В функциональном программировании типы позволяют точно описывать с какими значениями работают функции. Использование типов повышает гарантии корректности исполнения программ. Например, получив значение непредусмотренного для функции типа компилятор выдаст сообщение об ошибке.

Цитата:

... why we should care about types at all: what are they even for? At the lowest level, a computer is concerned with bytes, with barely any additional structure. What a type system gives us is abstraction. A type adds meaning to plain bytes: it lets us say “these bytes are text”, “those bytes are an airline reservation”, and so on. Usually, a type system goes beyond this to prevent us from accidentally mixing types up: for example, a type system usually won't let us treat a hotel reservation as a car rental receipt.

источник

Ссылки

Алгебраический тип данных

Составной тип, который получается путем из соединения нескольких других типов. Соединение типов называется алгеброй, что повлияло на название термина. Чаще всего рассматриваются тип-сумма и тип-произведение.

Тип-сумма (sum type)

Тип-сумма - это комбинация двух и более типов в новый тип таким образом, что число возможных значений в новом типе будет соответствовать сумме входящих элементов.

Булевский тип данных "правда-ложь" является самым простым типом-суммой:

data Bool = False | True

Три цвета светофора также тип-сумма:

data TrafficLight = Red | Yellow | Green

В примерах выше тип-сумма построен из простейших элементов, но эти элементы могут быть и более сложными. Тип Move описывает движение робота по прямой с целочисленными шагами вперед, назад или с остановкой.

data Move = Stop | Ahead Int | Back Int

Шаги робота теперь можно описать с помощью списка типа [Move], например, [Ahead 1, Stop, Stop, Back -2] (шаг вперед, два назад).

Типы Maybe и Either, использующиеся для управлениями эффектами вычислений, также являются типами-суммой.

Тип-произведение (product type)

Тип-произведение объединяет элементы таким образом, что количество новых значений представляет собой произведение возможных количеств входящих значений.

В большинстве языков программирования есть тип кортеж (tuple), который является самым простым типом-произведением. Например, кортеж из трех булевых значений типа (Bool, Bool, Bool) имеет 2*2*2 = 8 значений.

Привычные структры данных, например, записи с полями значений, также являются типами-произведением.

data Person = Person {name:String , age::Int} Person "LittleBaby" 2

Место точки на плоскости соcтоит их двух координат, которые можно выразить типом-произведением двух значений типа Float:

data Position = Position Float Float Position 1.5 2.8

Ссылки:

3. Общие понятия

Cсылочная прозрачность (referential transparency)

Выражение, которое можно заменить на его значение без изменения поведения программы, обладает свойством ссылочной прозрачности.

Cсылочная прозрачность упрощает понимание и изменение кода программ.

Ссылки:

Эквациональное рассуждение (equational reasoning)

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

Упорощенно, эквациональное рассуждение это процесс интерпретации или доказательства свойств кода программы путем подстановки равных выражений.

Ссылки:

Примечание: перевод термина дан по справочнику ruhaskell, часто используется в английском написании без перевода.

Выражение

Expression

Допустимый синтаксисом языка программирования набор переменных, операторов и функций, возвращающий значение.

Примеры выражений: 2+3, fst (1+2, 3+4), fmap (+1) (Just 5).

Ссылки:

Значение

Value

  1. Результат вычисления выражения.

  2. Все, что можно присвоить переменной.

Ленивые вычисления

Lazy evaluation

Механизм откладывания вычислений до момента, когда результат вычислений необходим для продолжения исполнения программы.

В функциональных языках ленивые вычисления позволяют, например, использовать такие структуры данных как бесконечные списки:

Prelude> let lst0 = [1..] Prelude> take 5 lst0 [1,2,3,4,5]

Литература

Другие англоязычные словари и глоссарии

Книги и сайты на русском языке

Развитие словаря

Что можно сделать в этом словаре лучше? Конечно, это решать читателям. Вы можете дать комментарий в issues этого проекта, или написать переводчику.

About

Jargon from the functional programming world in simple terms!

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Python 100.0%