Жаргон функционального программирования
У функционального программирования много преимуществ, и его популярность постоянно растет. Но, как и у любой парадигмы программирования, у ФП есть свой жаргон. Мы решили сделать небольшой словарь для всех, кто знакомится с ФП.
В примерах используется JavaScript ES2015). (Почему JavaScript?)
Работа над материалом продолжается; присылайте свои пулл-реквесты в оригинальный репозиторий на английском языке.
В документе используются термины из спецификации Fantasy Land spec по мере необходимости.
Arity (арность)
Количество аргументов функции. От слов унарный, бинарный, тернарный (unary, binary, ternary) и так далее. Это необычное слово, потому что состоит из двух суффиксов: «-ary» и «-ity.». Сложение, к примеру, принимает два аргумента, поэтому это бинарная функция, или функция, у которой арность равна двум. Иногда используют термин «диадный» (dyadic), если предпочитают греческие корни вместо латинских. Функция, которая принимает произвольное количество аргументов называется, соответственно, вариативной (variadic). Но бинарная функция может принимать два и только два аргумента, без учета каррирования или частичного применения.
Higher-Order Functions (функции высокого порядка)
Функция, которая принимает функцию в качестве аргумента и/или возвращает функцию.
Partial Application (частичное применение)
Частичное применение функции означает создание новой функции с пред-заполнением некоторых аргументов оригинальной функции.
Также в JS можно использовать Function.prototype.bind для частичного применения функции:
Благодаря предварительной подготовке данных частичное применение помогает создавать более простые функции из более сложных. Функции с каррированием автоматически выполняют частичное применение.
Currying (каррирование)
Процесс конвертации функции, которая принимает несколько аргументов, в функцию, которая принимает один аргумент за раз.
При каждом вызове функции она принимает один аргумент и возвращает функцию, которая принимает один аргумент до тех пор, пока все аргументы не будут обработаны.
Auto Currying (автоматическое каррирование)
Трансформация функции, которая принимает несколько аргументов, в новую функцию. Если в новую функцию передать меньшее чем предусмотрено количество аргументов, то она вернет функцию, которая принимает оставшиеся аргументы. Когда функция получает правильное количество аргументов, то она исполняется.
В Underscore, lodash и ramda есть функция curry .
Дополнительные материалы
Function Composition (композиция функций)
Соединение двух функций для формирования новой функции, в которой вывод первой функции является вводом второй.
Purity (чистота)
Функция является чистой, если возвращаемое ей значение определяется исключительно вводными значениями, и функция не имеет побочных эффектов.
Side effects (побочные эффекты)
У функции есть побочные эффекты если кроме возврата значения она взаимодействует (читает или пишет) с внешним изменяемым состоянием.
Idempotent (идемпотентность)
Функция является идемпотентной если повторное ее исполнение производит такой же результат.
Point-Free Style (бесточечная нотация)
Написание функций в таком виде, что определение не явно указывает на количество используемых аргументов. Такой стиль обычно требует каррирования или другой функции высокого порядка (или в целом — неявного программирования).
Функция incrementAll определяет и использует параметр numbers , так что она не использует бесточечную нотацию. incrementAll2 просто комбинирует функции и значения, не упоминая аргументов. Она использует бесточечную нотацию.
Определения с бесточечной нотацией выглядят как обычные присваивания без function или => .
Predicate (предикат)
Предикат — это функция, которая возвращает true или false в зависимости от переданного значения. Распространенный случай использования предиката — функция обратного вызова (callback) для фильтра массива.
Categories (категории)
Объекты с функциями, которые подчиняются определенным правилам. Например, моноиды.
Value (значение)
Все, что может быть присвоено переменной.
Constant (константа)
Переменная, которую нельзя переназначить после определения.
Константы обладают референциальной прозрачностью или прозрачностью ссылок (referential transparency). То есть, их можно заменить значениями, которые они представляют, и это не повлияет на результат.
С константами из предыдущего листинга следующее выражение выше всегда будет возвращать true .
Functor (функтор)
Объект, который реализует функцию map , которая при проходе по всем значениям в объекте создает новый объект, и подчиняется двум правилам:
( f , g — произвольные функции)
В JavaScript есть функтор Array , потому что он подчиняется эти правилам:
Pointed Functor (указывающий функтор)
Объект с функцией of с любым значением. В ES2015 есть Array.of , что делает массивы указывающим функтором.
Lifting — это когда значение помещается в объект вроде функтора. Если «поднять» (lift) функцию в аппликативный функтор, то можно заставить ее работать со значениями, которые также присутствуют в функторе.
В некоторых реализациях есть функция lift или liftA2 , которые используются для упрощения запуска функций на функторах.
Подъем функции с одним аргументом и её применение выполняет то же самое, что и map .
Referential Transparency (прозрачность ссылок)
Если выражение можно заменить его значением без влияния на поведение программы, то оно обладает прозрачностью ссылок.
Например, есть функция greet :
Любой вызов greet() можно заменить на Hello World! , так что эта функция является прозрачной (referentially transparent).
Lambda (лямбда)
Анонимная функция, которую можно использовать как значение.
Лямбды часто передают в качестве аргументов в функции высокого порядка.
Лямбду можно присвоить переменной.
Lambda Calculus (лямбда-исчисление)
Область информатики, в которой функции используются для создания универсальной модели исчисления.
Lazy evaluation (ленивые вычисления)
Механизм вычисления при необходимости, с задержкой вычисления выражения до того момента, пока значение не потребуется. В функциональных языках это позволяет создавать структуры вроде бесконечных списков, которые в обычных условиях невозможны в императивных языках программирования, где очередность команд имеет значение.
Monoid (моноид)
Объект с функцией, которая «комбинирует» объект с другим объектом того же типа. Простой пример моноида это сложение чисел:
В этом случае число — это объект, а + это функция.
Должен существовать нейтральный элемент (identity), так, чтобы комбинирование значения с ним не изменяло значение. В случае сложения таким элементом является 0 .
Также необходимо, чтобы группировка операций не влияла на результат (ассоциативность):
Конкатенация массивов — это тоже моноид:
Нейтральный элемент — это пустой массив []
Если существуют функции нейтрального элемента и композиции, то функции в целом формируют моноид:
foo — это любая функция с одним аргументом.
Monad (монада)
Монада — это объект с функциями of и chain . chain похож на map , но он производит разложение вложенных объектов в результате.
of также известен как return в других функциональных языках.
chain также известен как flatmap и bind в других языках.
Comonad (комонада)
Объект с функциями extract и extend .
Extract берет значение из функтора.
Extend выполняет функцию на комонаде. Функция должна вернуть тот же тип, что комонада.
Applicative Functor (аппликативный функтор)
Объект с функцией ap . ap применяет функцию в объекте к значению в другом объекте того же типа.
Это полезно, когда есть два объекта, и нужно применить бинарную операцию на их содержимом.
В итоге получим массив функций, которые можно вызвать с ap чтобы получить результат:
Morphism (морфизм)
Endomorphism (эндоморфизм)
Функция, у которой ввод и вывод — одного типа.
Isomorphism (изоморфизм)
Пара структурных трансформаций между двумя типами объектов без потери данных.
Например, двумерные координаты можно хранить в массиве [2,3] или объекте
Setoid
Объект, у которого есть функция equals , которую можно использовать для сравнения объектов одного типа.
Сделать массив сетоидом:
Semigroup (полугруппа)
Объект с функцией concat , которая комбинирует его с другим объектом того же типа.
Foldable
Объект, в котором есть функция reduce , которая трансформирует объект в другой тип.
Type Signatures (сигнатуры типа)
Часто функции в JavaScript содержат комментарии с указанием типов их аргументов и возвращаемых значений. В сообществе существуют разные подходы, но они все схожи:
Если функция принимает другую функцию в качестве аргумента, то ее помещают в скобки.
Символы a , b , c , d показывают, что аргументы могут быть любого типа. Следующая версия функции map принимает:
- функцию, которая трансформирует значение типа a в другой тип b
- массив значений типа a ,
и возвращает массив значений типа b .
Дополнительные материалы
Union type (тип-объединение)
Комбинация двух типов в один, новый тип.
В JavaScript нет статических типов, но давайте представим, что мы изобрели тип NumOrString , который является сложением String и Number .
Операция + в JavaScript работает со строками и числами, так что можно использовать наш новый тип для описания его ввода и вывода:
Тип-объединение также известно как алгебраический тип, размеченное объединение и тип-сумма.
Существует пара библиотек в JavaScript для определения и использования таких типов.
Product type (тип-произведение)
Тип-произведение комбинирует типы таким способом, который вам скорее всего знаком:
Его называют произведением, потому что возможное значение структуры данных это произведение (product) разных значений.
Option (опцион)
Тип-объединение с двумя случаями: Some и None . Полезно для композиции функций, которые могут не возвращать значения.
Используйте chain для построения последовательности функций, которые возвращают Option .
Option также известен как Maybe . Some иногда называют Just . None иногда называют Nothing .
Что такое предикат в программировании
Предикат — это функция, которая проверяет некоторое условие переданное в аргументах и возвращает nil, если условие ложное, или не-nil, если условие истинное. Можно рассматривать, что предикат производит булево значение, где nil обозначает ложь и все остальное — истину. Условные управляющие структуры, такие как cond, if, when и unless осуществляют проверку таких булевых значений. Мы говорим, что предикат истинен, когда он возвращает не-nil значение, и ложен, когда он возвращает nil, то есть он истинен или ложен в зависимости от того, истинно или ложно проверяемое условие.
По соглашению, имена предикатов обычно заканчиваются на букву p (которая обозначает «предикат (predicate)»). Common Lisp использует единое соглашение для использования дефисов в именах предикатов. Если имя предиката создано с помощью добавления p к уже существующему имени, такому как имя типа данных, тогда дефис помещается перед последним p тогда и только тогда, когда в исходном имени были дефисы. Например, number становится numberp, но standard-char становится standard-char-p. С другой стороны, если имя предиката сформировано добавлением префиксного спецификатора в начало существующего имени предиката, то два имени соединяются с помощью дефиса, и наличие или отсутствие перед завершающим p не изменяется. Например, предикат string-lessp не содержит дефиса перед p, потому что это строковая версия lessp. Имя string-less-p было бы некорректно указывающим на то, что это предикат проверяющий тип объекта называемого string-less, а имя stringlessp имело бы смысл того, что проверяет отсутствие строк в чем-либо.
Управляющие структуры, которые проверяют булевы значения, проверяют только является или нет значение ложью (nil). Любое другое значение рассматривается как истинное. Часто предикат будет возвращать nil, в случае «неудачи» и некоторое полезное значение в случае «успеха». Такие функции могут использоваться не только для проверки, но и также для использования полезного значения, получаемого в случае успеха. Например member.
Если лучшего, чем не-nil значения, в целях указания успеха не оказалось, по соглашению в качестве «стандартного» значения истины используется символ t.
Что такое предикатная функция?
Изучаю С++. В литературе одну из функций назвали предикатной. Что это может значить, или это такой перевод ?
Давайте рассмотрим такую задачу. У нас есть, скажем, вектор целых чисел, и мы хотим вывести на экран только положительные числа.
Как мы это сделаем?
А если вывести все, больше 5?
Похоже? Да. Так и тянет объединить их в
Но что, если мы захотим вывести только четные? Только те, для которых синус положителен?
Все это можно обобщить, например, так:
Где pred — функция, которая проверяет некоторое условие, предикат. И будут выведены только те числа, для которых функция pred вернет значение true . А как мы ее напишем — наше дело. Например,
Вот, по сути, и все. Остальное — функция, или лямбда, шаблон или нет, от скольки аргументов и т.д. и т.п. — не суть важно. Предикативная функция — проверяющая некоторое условие, предикат, для своего(их) аргумента(ов).
Ну и — предикаты весьма широко применяются в алгоритмах стандартной библиотеки.
Name already in use
Simple-Functional-Programming / predicate.md
- Go to file T
- Go to line L
- Copy path
- Copy permalink
- Open with Desktop
- View raw
- Copy raw contents Copy raw contents
Copy raw contents
Copy raw contents
Предикат — это функция, которая возвращает логическое значение (true или false), в зависимости от переданного ей значения. Предикаты часто используются в качестве аргумента для функции высшего порядка, которая занимается выборкой либо фильтрацией.
Пример предикатов в языке Python
В языке Python предикаты принято именовать начиная с «is» либо «has».
Пример предикатов в языке Scheme (GNU Guile)
В языке Scheme используется соглашение о том, что имя предиката должно заканчиваться на знак «?».