# Функции Вспомним функции в школьной математике. Они определялись следующим образом: $$f(x) = 3x - 2$$ Чтобы вычислить значение функции при конкретном $x$, значение подставлялось в определение функции, после чего вычислялся результат: $$\begin{aligned} f(1) &= 3 - 2 = 1 \\ f(5) &= 15 - 2 = 13 \end{aligned}$$ Посмотрим теперь на подобные определения не только как на способ задания математических функций, но и как на способ записи алгоритмов. Сначала нам необходимо отделить процесс вычисления от равенства значений. Пусть ${\color{red}u}$ и ${\color{red}v}$ это термы. Запись ${\color{red}u} \longrightarrow {\color{red}v}$ означает, что результатом применения шага вычисления к терму ${\color{red}u}$ является терм ${\color{red}v}$. Запись ${\color{red}u} \xrightarrow{\;*\;} {\color{red}v}$ же означает, что результатом применения произвольного количества шагов вычисления (включая нуль, поэтому ${\color{red}u} \xrightarrow{\;*\;} {\color{red}u}$) к терму ${\color{red}u}$ является терм ${\color{red}v}$. Теперь введём понятие вычислимой функции. Под вычислимой функцией мы понимаем сущность, которая, будучи применена к некоторому набору значений, вычисляется в некоторое выражение. Правило ${\color{red}f}({\color{red}x_1}, \dots, {\color{red}x_n}) := {\color{red}e}$ определяет вычислимую функцию, которая вычисляется точно так же, как и привычные нам функции — подстановкой значений на места переменных ${\color{red}x_1}, \dots, {\color{red}x_n}$ в ${\color{red}e}$. Знак $:=$ подчёркивает, что это правило является определением, а не произвольным равенством. Вычислимую функцию можно также задать правилом следующего вида: $$f(x) := \begin{cases} {\color{red}e_1}, &\text{если}\ {\color{red}c_1} \\ {\color{red}e_2}, &\text{если}\ {\color{red}c_2} \\ \dots \\ \end{cases}$$ В таком случае, функция вычисляется в выражение $\color{red}e_i$ в том случае, если высказывание $\color{red}c_i$ истинно для вычисленных значений аргументов функции. Вычисление сложного выражения сводится к вычислению его частей. Мы не будем фиксировать порядок вычисления: мы считаем, что терм $\color{red}u$ вычисляется в терм $\color{red}v$ в том случае, когда $\color{red}v$ может быть получено из $\color{red}u$ вычислением любой его части. Арифметические операции вычисляются как обычно. Приведём теперь пример нетривиальной вычислимой функции, решив следующую задачу. Пусть $a$ и $b$ это два положительных целых числа. Найдём наибольший общий делитель этих двух чисел, то есть наибольшее такое число $d$, что и $a$, и $b$ делятся на $d$ без остатка. Если если числа $a$ и $b$ равны, то тогда, очевидно, они и являются наибольшим общим делителем. В противном случае одно из чисел больше, пусть это будет $a$. Любое число $d$, что делит числа $a$ и $b$, также делит и их разность $a - b$ (действительно, если для некоторых $n$ и $k$ верно $a = n d$ и $b = k d$, то тогда $a - b = n d = k d = (n - k) d$ делится на $d$). Поэтому наибольший общий делитель $a$ и $b$ является также и наибольшим общим делителем чисел $a$ и $a - b$. Пользуясь этим рассуждением, определим следующую функцию: $$НОД(a, b) := \begin{cases} a, &\text{если}\ a = b \\ НОД(b, a - b), &\text{если}\ a > b \\ НОД(a, b - a), &\text{если}\ a < b \\ \end{cases}$$ Это функция представляет собой алгоритм Евклида, один из древнейших алгоритмов известных человечеству. Функция $НОД$ сводит нахождение наибольшего общего делителя двух чисел к поиску наибольшего общего делителя другой пары чисел. Подобное сведение задачи к иному варианту той же задачи называется *рекурсией.* Функция, которая упоминает себя в своём определении, соответственно, называется *рекурсивной.* Посмотрим теперь как вычисляется функция $НОД$, вычислив $НОД(18, 30)$: $$\begin{aligned} НОД(18, 30) &\xrightarrow{} НОД(18, 30 - 18) \\ &\xrightarrow{\;*\;} НОД(18, 12) \\ &\xrightarrow{\;*\;} НОД(12, 6) \\ &\xrightarrow{\;*\;} НОД(6, 6) \\ &\xrightarrow{\;*\;} 6 \end{aligned}$$ Функция $НОД$ применяется к паре положительных целых чисел. Но мы можем также определять функции, которые применяются к другим функциям. Рассмотрим суммы следующего вида: $$\sum_{n\leqslant i < k} f(i) = f(n) + \dots + f(k - 1)$$ Мы можем определить функцию $sum$, которая вычисляет такие суммы: $$sum(n, k, f) := \begin{cases} 0, &n ≥ k \\ sum(n, k - 1, f) + f(k-1), &n