Если вы такой же разработчик, как и я, то наверняка сперва изучали парадигму ООП. Первым вашим яыком были Java или C++ — или, если вам повезло, Ruby, Python или C# — поэтому вы наверняка знаете, что такое классы, объекты, экземпляры и т.д. В чём вы точно не особо разбираетесь, так это в основах той странной парадигмы, называющейся функциональным программированием, которая существенно отличается не только от ООП, но и от процедурного, прототипно-ориентированного и других видов программирования.
Функциональное программирование становится популярным — и на то есть причины. Сама парадигма не нова: Haskell, пожалуй, является самым функциональным языком, а возник он в 90-ых. Такие языки, как Erlang, Scala, Clojure также попадают под определение функциональных. Одним из основных преимуществ функционального программирования является возможность написания программ, работающих конкурентно (если вы уже забыли, что это — освежите память прочтением статьи о конкурентности), причём без ошибок — то есть взаимные блокировки и потокобезопасность вас не побеспокоят.
Основы программирования. Урок 6 — Функции. Для новичков!
У функционального программирования есть много преимуществ, но возможность максимального использования ресурсов процессора благодаря конкурентному поведению — это его главный плюс. Ниже мы рассмотрим основные принципы функционального программирования.
Вступление: Все эти принципы не обязательны (многие языки следуют им не полностью). Все они теоретические и нужны для наиболее точного определения функциональной парадигмы.
1. Все функции — чистые
Это правило безусловно является основным в функциональном программировании. Все функции являются чистыми, если они удовлетворяют двум условиям:
- Функция, вызываемая от одних и тех же аргументов, всегда возвращает одинаковое значение.
- Во время выполнения функции не возникают побочные эффекты.
Первое правило понятно — если я вызываю функцию sum(2, 3) , то ожидаю, что результат всегда будет равен 5. Как только вы вызываете функцию rand() , или обращаетесь к переменной, не определённой в функции, чистота функции нарушается, а это в функциональном программировании недопустимо.
Второе правило — никаких побочных эффектов — является более широким по своей природе. Побочный эффект — это изменение чего-то отличного от функции, которая исполняется в текущий момент. Изменение переменной вне функции, вывод в консоль, вызов исключения, чтение данных из файла — всё это примеры побочных эффектов, которые лишают функцию чистоты.
Может показаться, что это серьёзное ограничение, но подумайте ещё раз. Если вы уверены, что вызов функции не изменит ничего «снаружи», то вы можете использовать эту функцию в любом сценарии. Это открывает дорогу конкурентному программированию и многопоточным приложениям.
2. Все функции — первого класса и высшего порядка
Эта концепция — не особенность ФП (она используется в Javascript, PHP и других языках) — но его обязательное требование. На самом деле, на Википедии есть целая статья, посвящённая функциям первого класса. Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной. Это позволяет управлять функцией как обычным типом данных и в то же время исполнять её.
ЯЗЫКИ ПРОГРАММИРОВАНИЯ. ЧТО НУЖНО ЗНАТЬ!
Функции высшего порядка же определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию. Типичными примерами таких функций являются map и filter.
3. Переменные неизменяемы
Тут всё просто. В функциональном программировании вы не можете изменить переменную после её инициализации. Вы можете создавать новые, но не можете изменять существующие — и благодаря этому вы можете быть уверены, что никакая переменная не изменится.
4. Относительная прозрачность функций
Сложно дать корректное определение относительной прозрачности. Самым точным я считаю такое: если вы можете заменить вызов функции на возвращаемое значение, и состояние при этом не изменится, то функция относительно прозрачна. Это, быть может, очевидно, но я приведу пример.
Пусть у нас есть Java-функция, которая складывает 3 и 5:
public int addNumbers() < return 3 + 5; >addNumbers() // 8 8 // 8
Очевидно, что любой вызов этой функции можно заменить на 8 — значит, функция относительно прозрачна. Вот пример непрозрачной функции:
public void printText() < System.out.println(«Hello World»); >printText() // Returns nothing, but prints «Hello World»
Эта функция ничего не возвращает, но печатает текст, и при замене вызова функции на ничто состояние консоли будет другим — значит, функция не является относительно прозрачной.
5. Функциональное программирование основано на лямбда-исчислении
Функциональное программирование сильно опирается на математическую систему, называющуюся лямбда-исчислением. Я не математик, поэтому я не буду углубляться в детали — но я хочу обратить внимание на два ключевых принципа лямбда-исчисления, которые формируют самое понятие функционального программирования:
- В лямбда-исчислении все функции могут быть анонимными, поскольку единственная значимая часть заголовка функции — это список аргументов.
- При вызове все функции проходят процесс каррирования. Он заключается в следующем: если вызывается функция с несколькими аргументами, то сперва она будет выполнена лишь с первым аргументом и вернёт новую функцию, содержащую на 1 аргумент меньше, которая будет немедленно вызвана. Этот процесс рекурсивен и продолжается до тех пор, пока не будут применены все аргументы, возвращая финальный результат. Поскольку функции являются чистыми, это работает.
Как я уже говорил, лямбда-исчисление на этом не заканчивается — но мы рассмотрели лишь ключевые аспекты, связанные с ФП. Теперь, в разговоре о функциональном программировании вы сможете блеснуть словечком «лямбда-исчисление», и все подумают, что вы шарите
Функциональное программирование серьёзно напрягает мозги — но это очень мощный подход, и я считаю, что его популярность будет только расти.
Если вы хотите узнать о функциональном программировании побольше, то советуем вам ознакомиться с примерами использования принципов ФП в JavaScript (часть 1, часть 2), а также с циклом статей, посвящённым функциональному C#.
Источник: tproger.ru
Лабораторная работа № 9 Программирование с использованием функций
Цель работы: 1) изучить правила описания функций; 2) приобрести навыки использования функций при написании программ на языкеC++.
Теоретические сведения
Основным модулем программ в языке С++ является функция.
Функция- логически завершенный, определенным образом оформленный фрагмент программы, имеющий имя. Функции позволяют разделить большие вычислительные задачи на более мелкие.
Каждая программа на языке С++ обязательно содержит функцию с именем main (главная), которая является телом программы. Для всех остальных функций, если они присутствуют в программе, следует объявлять прототипы — схематические записи, которые сообщают компилятору имя и форму каждой функции в программе.
Синтаксис для прототипа функций с параметрами:
тип_возвращаемого_значения имя_функции (список_параметров_с_указанием_типов);
Функции в С++ бывают стандартные (библиотечные) и программируемые пользователем.
Стандартные функции
Описания стандартных функций находятся в файлах, включаемых в программу с помощью директивы #include. Такие файлы называют заголовочными; они имеют расширение h.
Обращение к имени функции в основной программе называется вызовом функции.
Вызов функций приводит к выполнению некоторых действий или вычислению некоторой величины, используемой затем в программе.
y = sin (x); //функция вычисления синуса
Определение функции
В общем виде функции определяются следующим образом:
тип_возвращаемого_значения имя_функции (тип имя_параметра. тип имя_параметра)
тело_функции
Программируемые функции
Функции, которые программист создает сам, упрощают процесс написания программ, поскольку они:
- помогают избежать повторного программирования, так как одну и ту же функцию можно применять в различных программах;
- повышают уровень модульности программы, следовательно, облегчают ее чтение, внесение изменений и коррекцию ошибок.
Параметры функций
Рассмотрим на примере использование параметров функции. Пример 9.2.
Напишем функцию space(), в качестве аргумента которой будет число пробелов, которое должна напечатать эта функция. #define address » Zelenograd» #define name » Moscow Institute Electronic Engineering » #define department » Informatics and Programming» const int LIMIT=65; #include void stars(); void space(int number); void main() < int spaces; stars(); space(25); cout//Определение функции stars() void stars() < int count; for (count=1; count//Определение функции space() void space(int number) < int count; for (count=1; count Переменная number называется формальным аргументом. Эта переменная приобретает значения фактического аргумента при вызове функции. Другими словами, формальный аргумент- переменная в определении вызываемой подпрограммы, афактический аргумент- конкретное значение, присвоенное этой переменной вызывающей программой. Если для связи с некоторой функцией требуется более одного аргумента, то наряду с именем функции можно задать список аргументов, разделенных запятыми: void printnum (int i, int j) < coutВходная величина функции может обрабатываться благодаря наличию аргумента; выходная величина возвращается при помощи ключевого словаreturn.
Источник: studfile.net
sampletext32 / Func.md
Математические функции выражают связь между исходными данными и итоговым продуктом некоторого процесса.
Процесс вычисления также имеет вход и выход, поэтому функция — вполне подходящее и адекватное средство описания вычислений.
Именно этот простой принцип положен в основу функциональной парадигмы и функционального стиля программирования.
- Множество допустимых входных значений функции называются domain (область определения).
- Множество возможных результатов функции (область значений) называется range (технически, изображение codomain-а).
- Функцией называют отображение (в оригинале map) из domain-а в range. (Т.е. из области определения в область значений.)
В математическом понимании функция является правилом сопоставления каждому элементу области определения функции в точности одного элемента из области значений
05. История и основные вехи функционального программирования
- Теория, положенная в основу функционального подхода, родилась в 20-х — 30-х годах.
- В числе разработчиков математических основ функционального программирования можно назвать Моисея Шейнфинкеля и Хаскелла Карри, разработавших комбинаторную логику, и Алонзо Чёрча, создателя лямбда-исчисления.
- В конце 1950-х годов Джон Маккарти разработал язык Лисп, который стал первым почти функциональным языком программирования и многие годы оставался единственным таковым.
- В конце 70-х — начале 80-х годов XX века интенсивно разрабатываются модели типизации, подходящие для функциональных языков.
- Большинство этих моделей включали в себя поддержку таких мощных механизмов как абстракция данных и полиморфизм.
- Появляется множество типизированных функциональных языков: ML, Scheme, Hope, Miranda, Clean и многие другие. Вдобавок постоянно увеличивается число диалектов.
06. Свойства и характеристики функционального программирования
- Все функции — чистые
- Все функции — первого класса и высшего порядка
- Переменные неизменяемы
- Относительная прозрачность функций
- Функциональное программирование основано на лямбда-исчислении
07. Чистые функции. Примеры.
Все функции являются чистыми, если они удовлетворяют двум условиям:
- Функция, вызываемая от одних и тех же аргументов, всегда возвращает одинаковое значение.
- Во время выполнения функции не возникают побочные эффекты.
- Вызывая функцию sum(2, 3), вы ожидаете, что результат всегда будет равен 5.
- Как только вы вызываете функцию rand(), или обращаетесь к переменной, не определённой в функции, чистота функции нарушается, а это в функциональном программировании недопустимо.
// самый простой пример — увеличение числа на 1, // не изменяется при передаче одинаковых значений // не создаёт побочные эффекты var add1 = y => y + 1;
08. Побочные эффекты. Проблемы и особенности.
Побочный эффект — это изменение чего-то отличного от функции, которая исполняется в текущий момент.
- Изменение переменной вне функции
- Вывод в консоль
- Вызов исключения
- Чтение данных из файла
— всё это примеры побочных эффектов, которые лишают функцию чистоты.
- Если вы уверены, что вызов функции не изменит ничего «снаружи», то вы можете использовать эту функцию в любом сценарии. Это открывает дорогу конкурентному программированию и многопоточным приложениям.
Сила чистых функций:
- Их легко распараллелить. Скажем, можно бы взять целые числа в диапазоне от 1 до 1000 и раздать их 1000 различных процессоров, после чего поручить каждому CPU выполнить add1 над соответствующим числом, одновременно будучи уверенным, что нет необходимости в каком-либо взаимодействии между ними. Не потребуется ни блокировок, ни мьютексов, ни семафоров, ни т.п.
- Можно использовать функции лениво, вычисляя их тогда, когда это необходимо для логики программы. Можно быть уверенным, что ответ будет точно таким же, независимо от того, проводятся вычисления сейчас или позже.
- Можно лишь один раз провести вычисления функции для конкретного входа, после чего закешировать результат, потому что известно, что данные входные значения будут давать такой же выход.
- Их можно вычислять в любом порядке если есть множество чистых функций. Опять же, это не может повлиять на финальный результат.
09. Функции первого и высшего порядка. Проблемы и особенности.
- Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной.
Это позволяет управлять функцией как обычным типом данных и в то же время исполнять её.
- Функции высшего порядка определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию.
Типичными примерами таких функций являются map и filter .
10. Переменные в функциональном программировании.
- Переменная в лямбда-исчислении — это то же самое что переменная в любом языке программирования, контейнер для какого-то значения.
- Область видимости переменной определяется ближайшей функцией или скобками.
- Переменные в лямбда-исчислении могут быть свободными или связанными.
- Связанная переменная — это переменная, которая используется в области видимости, после того как она была объявлена в аргументах ближайшей функции, в иных случаях она свободна.
11. Состояние функций в функциональном программировании.
Функция — это описание процесса, связывающего вход с каким-то выводом.
Так же как в любом другом языке программирования.
Сверх этого, все функции в лямбда-исчислении:
- анонимные, то есть не могут иметь имен
- могут принимать только одну переменную, то есть их арность всегда равна 1
- являются “объектами первого класса”, то есть могут быть входными и выходными значениями в функциях
12. Лямбда исчисление
- Лямбда-исчисление — это формальная система в математической логике для описания вычислений с помощью абстракции и аппликации функций, использующая связывание переменных и подстановку
- Любой функциональный язык программирования — это надстройка над лямбда-исчислением
- Основные понятия в лямбда-исчислении это: переменные, лямбда термы, аппликация и абстракция.
- Абстракция — это просто объявление функции. Оно обозначается символом λ. После этого символа Вы пишете входные переменные функции, потом точку и вывод функции, в котором Вы описываете, что ожидаете получить (то есть, это одновременно и тело функции).
- Переменная в лямбда-исчислении — это то же самое что переменная в любом языке программирования, контейнер для какого-то значения. Область видимости переменной определяется ближайшей функцией или скобками. Переменные в лямбда-исчислении могут быть свободными или связанными. Связанная переменная — это переменная, которая используется в области видимости, после того как она была объявлена в аргументах ближайшей функции, в иных случаях она свободна.
- Здесь “x” связана, а “y” свободна: λx.xy
- К примеру, терм идентичности (вход такой же как вывод) определяется вот так: I := λx.x
- анонимные, то есть не могут иметь имен
- могут принимать только одну переменную, то есть их арность всегда равна 1 являются “объектами первого класса”, то есть могут быть входными и выходными значениями в функциях
- Как можно сделать что-либо полезное без функций с двумя (или более) параметрами?
- Ответ довольно прост: функция с несколькими параметрами переписывается как серия новых функций, каждая из которых принимает только один параметр. Эту операцию компилятор выполняет автоматически, и называется она «каррирование» (currying), в честь Хаскела Карри, математика, который существенно повлиял на разработку функционального программирования.
- При вызове каррированной функции с передачей ей одного аргумента, она возвращает новую функцию, которая ожидает поступления следующего аргумента.
13. Лямбда выражение в C#
Лямбда выражения — это анонимная функция, содержащая выражения и операторы
- Используется лямбда-оператор => (goes to)
- Параметры передаются в круглых скобках ()
- Тело «функции» содержит выражение или утверждение и может быть заключено в фигурные скобки <>
- Неявное лямбда-выражение
msg => Console.WriteLine(msg) ;
(string msg) => Console.WriteLine(msg); >
() => Console.WriteLine(«hi»); >
() => MyMethod() ;
(int x, int y) => return x + y; >
14. Делегаты – особенности и отличие от функций.
- Делегат – типизированная ссылка на метод с определенным списком параметров и типом возвращаемого значения
- Используется для передачи методов в качестве аргументов другим методам
- Может использоваться для определения «callback» методов
15. Обобщенный делегат Func в C#
- Инициализация функции
Funcint, string> func = n => n.ToString();
16. Обобщенный делегат Action в C#
Инкапсулирует метод, который не имеет параметров и не возвращает значений.
- Action не имеет параметров
- Action может иметь параметры
По простому – ссылка на void метод:
private void Print(string message) Console.WriteLine(message); >
Такая же функция в виде делегата Action
Actionstring> print = message => Console.WriteLine(message);
17. Делегат как параметр функции