Light-electric.com

IT Журнал
48 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Программирование с помощью функций

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

    Переводы, 23 января 2017 в 13:43

Если вы такой же разработчик, как и я, то наверняка сперва изучали парадигму ООП. Первым вашим яыком были Java или C++ — или, если вам повезло, Ruby, Python или C# — поэтому вы наверняка знаете, что такое классы, объекты, экземпляры и т.д. В чём вы точно не особо разбираетесь, так это в основах той странной парадигмы, называющейся функциональным программированием, которая существенно отличается не только от ООП, но и от процедурного, прототипно-ориентированного и других видов программирования.

Функциональное программирование становится популярным — и на то есть причины. Сама парадигма не нова: Haskell, пожалуй, является самым функциональным языком, а возник он в 90-ых. Такие языки, как Erlang, Scala, Clojure также попадают под определение функциональных. Одним из основных преимуществ функционального программирования является возможность написания программ, работающих конкурентно (если вы уже забыли, что это — освежите память прочтением статьи о конкурентности), причём без ошибок — то есть взаимные блокировки и потокобезопасность вас не побеспокоят.

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

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

1. Все функции — чистые

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

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

Первое правило понятно — если я вызываю функцию sum(2, 3) , то ожидаю, что результат всегда будет равен 5. Как только вы вызываете функцию rand() , или обращаетесь к переменной, не определённой в функции, чистота функции нарушается, а это в функциональном программировании недопустимо.

Второе правило — никаких побочных эффектов — является более широким по своей природе. Побочный эффект — это изменение чего-то отличного от функции, которая исполняется в текущий момент. Изменение переменной вне функции, вывод в консоль, вызов исключения, чтение данных из файла — всё это примеры побочных эффектов, которые лишают функцию чистоты. Может показаться, что это серьёзное ограничение, но подумайте ещё раз. Если вы уверены, что вызов функции не изменит ничего “снаружи”, то вы можете использовать эту функцию в любом сценарии. Это открывает дорогу конкурентному программированию и многопоточным приложениям.

2. Все функции — первого класса и высшего порядка

Эта концепция — не особенность ФП (она используется в Javascript, PHP и других языках) — но его обязательное требование. На самом деле, на Википедии есть целая статья, посвящённая функциям первого класса. Для того, чтобы функция была первоклассной, у неё должна быть возможность быть объявленной в виде переменной. Это позволяет управлять функцией как обычным типом данных и в то же время исполнять её.

Функции высшего порядка же определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию. Типичными примерами таких функций являются map и filter.

3. Переменные неизменяемы

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

4. Относительная прозрачность функций

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

Пусть у нас есть Java-функция, которая складывает 3 и 5:

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

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

5. Функциональное программирование основано на лямбда-исчислении

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

  1. В лямбда-исчислении все функции могут быть анонимными, поскольку единственная значимая часть заголовка функции — это список аргументов.
  2. При вызове все функции проходят процесс каррирования. Он заключается в следующем: если вызывается функция с несколькими аргументами, то сперва она будет выполнена лишь с первым аргументом и вернёт новую функцию, содержащую на 1 аргумент меньше, которая будет немедленно вызвана. Этот процесс рекурсивен и продолжается до тех пор, пока не будут применены все аргументы, возвращая финальный результат. Поскольку функции являются чистыми, это работает.

Как я уже говорил, лямбда-исчисление на этом не заканчивается — но мы рассмотрели лишь ключевые аспекты, связанные с ФП. Теперь, в разговоре о функциональном программировании вы сможете блеснуть словечком “лямбда-исчисление”, и все подумают, что вы шарите ?

Заключение

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

Если вы хотите узнать о функциональном программировании побольше, то советуем вам ознакомиться с примерами использования принципов ФП в JavaScript (часть 1, часть 2), а также с циклом статей, посвящённым функциональному C#.

Читать еще:  A b c программирование

Работа с функциями пользователя в языке программирования С++

технические науки

  • Хусаинов Исмагильян Гарифьянович , доктор наук, доцент, профессор
  • Башкирский государственный университет, Стерлитамакский филиал
  • Похожие материалы

    Одними из самыми распространенными языками программирования высокого уровня являются Си и С++ [1, 2]. Эти языки программирования пользуются успехов у студентов. Они используются студентами при выполнении курсовых проектов, написании выпускных квалификационных работ [3, 4]. Кроме того, язык программирования С++ используются при решении многих научных задач [5-7].

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

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

    Функция объединяет объявления и операторы. Она оформляется в виде отдельной конструкции и снабжается именем. Имя функции применяется для её объявления, определения и вызова. В языке С++ функция не может быть описана внутри другой функции.

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

    Общий вид описания функции пользователя:

    Элементы указанные в квадратных скобках могут отсутствовать. Спецификатор задает класс памяти функции пользователя, например, static или extern. класс памяти

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

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

    Спецификатор задает тип возвращаемого значения. Если спецификатор отсутствует, то по умолчанию функция возвращает значение типа int. Функция типа void результат не возвращает, а выполняет некоторые действия.

    Возвращаемое значение указывается после оператора return. После return указывается выражение. Вычисляется значение выражения, преобразуется к типу возвращаемого значения функцией. Вычисленное значение возвращается в точку вызова функции в качестве результата.

    После выполнения оператора return функция завершает свою работу. Общий вид оператора return:

    Если функция возвращает значение типа void, то в операторе return должно отсутствовать:

    — это последовательность формальных параметров, разделенных запятыми. Формальные параметры являются переменными, которые используются внутри тела функции и получают свои значения при вызове функции от фактических параметров. Между двумя формальными параметрами ставиться запятая.

    Примеры объявления функций с несколькими параметрами:

    Если у функции нет параметров, то круглые скобки после имени функции обязательно указываются. Вместо пустого списка параметров можно указать слово void:

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

    Рассмотрим примеры передачи массивов функциям в качестве параметров.

    Первый параметр функции Function — это массив, а второй — количество элементов массива. При вызове функции передаем реальные параметры

    Пример. Дан одномерный вещественный массив, содержащий 20 элементов. Найти наибольший элемент массива.

    Решение задачи. В статье специально все программы приводятся в элементарном виде, чтобы она была понятна для начинающих программистов.

    Пример. Дан одномерный вещественный массив, содержащий 20 элементов. Отсортировать элементы массива по неубыванию.

    Массив является указателем, и поэтому функции sort_massiv массив mas передается по ссылке. При передаче массива функции в качестве параметра все изменения в значениях элементов массива внутри функции сохраняются после выхода из функции.

    Для передачи массивов в функцию можно использовать указатели.

    Пример. Дан двумерный целочисленный массив, содержащий 5 строк и 4 столбца. Вывести на экран номер строки и сумму элементов этой строки в столбик.

    Таким образом, в статье на понятном для начинающего программиста уровне рассматривается создание функции пользователя в языке программирования С++. Приведены примеры решения задач с помощью функций. Рассмотрена тема передача массивов функции в качестве параметра.

    Список литературы

    1. Дубров Г.В. Основы программирования на С++. – М.: Конкорд, 1993. – 219 c.
    2. Подбельский В.В. Язык С++: Учебное пособие – 5 изд. – М: Финансы и статистика, 2004. – 560 c.
    3. Шилдт Г. С++: базовый курс. 3-е издание. – М.: Издательский дом «Вильямс». 2010. – 624 с.
    4. Хусаинова Г.Я. Этапы проектирования информационной системы // Вестник Технологического университета. 2018. Т. 21. № 6. – С. 153-156.
    5. Хусаинов И.Г/ Исследование влияния круговой границы на процесс релаксации давления в скважине после её опрессовки // Автоматизация. Современные технологии. 2017. Т. 71. № 11. – С. 490-494.
    6. Хусаинов И.Г. Релаксация температуры пластины, помещенной в среду с более низкой температурой // Вестник Тюменского государственного университета. Физико-математическое моделирование. Нефть, газ, энергетика. 2017. Т. 3. № 4. – С. 132-141
    7. Хусаинова Г.Я. Нестационарная фильтрация вязкопластичной жидкости в пласте // Автоматизация. Современные технологии. 2018. Т. 72. № 4. – С. 147-149.

    Электронное периодическое издание зарегистрировано в Федеральной службе по надзору в сфере связи, информационных технологий и массовых коммуникаций (Роскомнадзор), свидетельство о регистрации СМИ — ЭЛ № ФС77-41429 от 23.07.2010 г.

    Соучредители СМИ: Долганов А.А., Майоров Е.В.

    Функции в языке Си

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

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

    Семантика функции определяет способ реализации функции. Обычно представляет собой тело функции.

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

    Каждая функция в языке Си должна быть определена, то есть должны быть указаны:

    • тип возвращаемого значения;
    • имя функции;
    • информация о формальных аргументах;
    • тело функции.

    Определение функции имеет следующий синтаксис:

    Пример : Функция сложения двух вещественных чисел

    В указанном примере возвращаемое значение имеет тип float . В качестве возвращаемого значения в вызывающую функцию передается значение переменной y . Формальными аргументами являются значения переменных x и z .

    Если функция не возвращает значения, то тип возвращаемого значения для нее указывается как void . При этом операция return может быть опущена. Если функция не принимает аргументов, в круглых скобках также указывается void .

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

    Системные функции хранятся в стандартных библиотеках, и пользователю не нужно вдаваться в подробности их реализации. Достаточно знать лишь их сигнатуру. Примером системных функций, используемых ранее, являются функции printf() и scanf() .

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

    Разбиение программ на функции дает следующие преимущества:

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

    С точки зрения вызывающей программы функцию можно представить как некий «черный ящик», у которого есть несколько входов и один выход. С точки зрения вызывающей программы неважно, каким образом производится обработка информации внутри функции. Для корректного использования функции достаточно знать лишь ее сигнатуру.

    Вызов функции

    Общий вид вызова функции

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

    Возврат в вызывающую функцию

    По окончании выполнения вызываемой функции осуществляется возврат значения в точку ее вызова. Это значение присваивается переменной, тип которой должен соответствовать типу возвращаемого значения функции. Функция может передать в вызывающую программу только одно значение. Для передачи возвращаемого значения в вызывающую функцию используется оператор return в одной из форм:

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

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

    Функции могут и не возвращать значения, а просто выполнять некоторые вычисления. В этом случае указывается пустой тип возвращаемого значения void , а оператор return может либо отсутствовать, либо не возвращать никакого значения:

    Пример : Посчитать сумму двух чисел.

    В языке Си нельзя определять одну функцию внутри другой.

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

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

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

    Если в примере выше тело функции сложения чисел разместить после тела функции main, то код будет выглядеть следующим образом:

    Рекурсивные функции

    Функция, которая вызывает сама себя, называется рекурсивной функцией .

    Рекурсия — вызов функции из самой функции.

    Пример рекурсивной функции — функция вычисления факториала.

    Элементы функционального программирования

    Функции являются абстракциями, в которых детали реализации некоторого действия скрываются за отдельным именем. Хорошо написанный набор функций позволяет использовать их много раз. Стандартная библиотека Python содержит множество готовых и отлаженных функций, многие из которых достаточно универсальны, чтобы работать с широким спектром входных данных. Даже если некоторый участок кода не используется несколько раз, но по входным и выходным данным он достаточно автономен, его смело можно выделить в отдельную функцию.

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

    Далее будут подробно рассмотрены описание и использование функций в Python , рекурсия , передача и возврат функций в качестве параметров, обработка последовательностей и итераторы , а также такое понятие как генератор . Будет продемонстрировано, что в Python функции являются объектами (и, значит, могут быть переданы в качестве параметров и возвращены в результате выполнения функций). Кроме того, речь пойдет о том, как можно реализовать некоторые механизмы функционального программирования, не имеющие в Python прямой синтаксической поддержки, но широко распространенные в языках функционального программирования.

    Что такое функциональное программирование?

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

    Как отмечает Дэвид Мертц (David Mertz) в своей статье о функциональном программировании на Python , «функциональное программирование — программирование на функциональных языках ( LISP , ML, OCAML, Haskell, . )», основными атрибутами которых являются:

    • «Наличие функций первого класса» (функции наравне с другими объектами можно передавать внутрь функций).
    • Рекурсия является основной управляющей структурой в программе.
    • Обработка списков (последовательностей).
    • Запрещение побочных эффектов у функций, что в первую очередь означает отсутствие присваивания (в «чистых» функциональных языках)
    • Запрещение операторов, основной упор делается на выражения. Вместо операторов вся программа в идеале — одно выражение с сопутствующими определениями.
    • Ключевой вопрос: что нужно вычислить, а не как.
    • Использование функций более высоких порядков (функции над функциями над функциями).

    Функциональная программа

    В математике функция отображает объекты из одного множества ( множества определения функции ) в другое ( множество значений функции ). Математические функции (их называют чистыми ) «механически», однозначно вычисляют результат по заданным аргументам. Чистые функции не должны хранить в себе какие-либо данные между двумя вызовами. Их можно представлять себе черными ящиками, о которых известно только то, что они делают, но совсем не важно, как.

    Программы в функциональном стиле конструируются как композиция функций. При этом функции понимаются почти так же, как и в математике: они отображают одни объекты в другие. В программировании «чистые» функции — идеал, не всегда достижимый на практике. Практически полезные функции обычно имеют побочный эффект: сохраняют состояние между вызовами или меняют состояние других объектов. Например, без побочных эффектов невозможно представить себе функции ввода-вывода. Собственно, такие функции ради этих «эффектов» и используются. Кроме того, математические функции легко работают с объектами, требующими бесконечного объема информации (например, вещественные числа). В общем случае компьютерная программа может выполнить лишь приближенные вычисления.

    Кстати, бинарные операции » + «, » — «, » * «, » / «, которые записываются в выражениях, являются «математическими» функциями над двумя аргументами — операндами. Их используют настолько часто, что синтаксис языка программирования имеет для них более короткую запись . Модуль operator позволяет представлять эти операции в функциональном стиле:

    Функции (functions) в C++: перегрузки и прототипы

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

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

    Что такое функции

    Функции — это блок кода, который вы можете использовать в любом участке вашей программы неограниченное количество раз. Например, в программе ниже мы выводим 2 строки (без применения функций):

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

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

    Как создать функции в C++

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

    Давайте разберем эту конструкцию:

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

    Если вы не знали main() — это тоже функция.

    Как вызывать функцию

    Для вызова функций вам нужно использовать такую конструкцию:

    Например, выше для вызова функции stroka() (эта функция находится выше) нам нужно использовать такую конструкцию:

    Как видите, мы не вписывали аргументы в круглые скобки, так как мы их не указали при создании функции.

    Зачем использовать функции

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

    Дело в том, что, если вы не используете функции, то программа становится менее мобильной. Например, конкретная ситуация. Вы работаете над проектом и уже написали несколько тысяч строк кода, затем решили изменить вывод сообщения с «Привет!» на «Привет дорогой читатель!» . Для этого вам придется найти все строки, в которых происходит вывод сообщения и изменить их все.

    А если бы вы использовали функцию, которая выводила сообщение «Привет!», то тогда бы вам пришлось только найти эту функцию и изменить ее!

    Перегрузка функций

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

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

    • Имя функции.
    • Число аргументов функции.
    • Типы аргументов.

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

    Перегрузка функций — это создание функций с одинаковыми именами, но с разными сигнатурами (полными именами).

    В примере ниже все функции разные, хотя и имена у них одинаковые:

    0 0 голоса
    Рейтинг статьи
Ссылка на основную публикацию
ВсеИнструменты