Редактировать: Хотя я, по-видимому, пропустил яблочко по фактическому вопросу, я думаю, что мой ответ довольно хороший, поэтому я его держу :-) (см. Ниже).
Я думаю, что более краткий способ сформулировать вопрос может быть следующим: может ли чисто функциональный язык вычислить все, что может сделать императив?
Прежде всего, предположим, что вы выбрали императивный язык, такой как C, и сделали так, чтобы вы могли 'изменить переменные после их определения.Например:
int i;
for (i = 0; // okay, that's one assignment
i < 10; // just looking, that's all
i++) // BUZZZ! Sorry, can't do that!
Ну вот и пошла ваша for
петля.Разве мы можем сохранить наш while
цикл?
while (i < 10)
Конечно, но это не очень полезно.i
не может измениться, поэтому он либо будет работать вечно, либо не будет работать вообще.
Как насчет рекурсии?Да, вы можете сохранить рекурсию, и это все еще очень полезно:
int sum(int *items, unsigned int count)
{
if (count) {
// count the first item and sum the rest
return *items + sum(items + 1, count - 1);
} else {
// no items
return 0;
}
}
Теперь, с помощью функций, мы не изменяем состояние, но переменные могут, ну, в общем, изменяться.Как только переменная попадает в нашу функцию, она блокируется. Однако мы можем снова вызвать функцию (рекурсия), и это похоже на получение нового набора переменных (старые остаются прежними).Хотя существует несколько экземпляров items
и count
, sum((int[]){1,2,3}, 3)
всегда будет иметь значение 6
, поэтому вы можете заменить это выражение на 6
, если хотите.
Можем ли мы что-нибудь еще сделать?мы хотим?Я не уверен на 100%, но я думаю, что ответ «да».Вы, конечно, можете, если у вас есть закрытие.
Вы правильно поняли.Идея в том, что после определения переменной ее нельзя переопределить.Относительно прозрачное выражение, учитывая одинаковые переменные, всегда дает одно и то же значение результата.
Я рекомендую изучить Haskell, чисто функциональный язык.На Хаскеле, строго говоря, нет оператора «присваивания».Например:
my_sum numbers = ??? where
i = 0
total = 0
Здесь вы не можете написать цикл for, который увеличивает i и total по мере продвижения.Однако еще не все потеряно.Просто используйте рекурсию, чтобы получать новые i
s и total
s:
my_sum numbers = f 0 0 where
f i total =
if i < length numbers
then f i' total'
else total
where
i' = i+1
total' = total + (numbers !! i)
(Обратите внимание, что это глупый способ суммировать список в Haskell, но он демонстрирует методсправиться с одним заданием.)
Теперь рассмотрим этот крайне императивный код:
main = do
a <- readLn
b <- readLn
print (a + b)
Это на самом деле синтаксический сахар для:
main =
readLn >>= (\a ->
readLn >>= (\b ->
print (a + b)))
Идея состоит в том, что вместо main, являющегося функцией, состоящей из списка операторов, main - это IO-действие, которое выполняет Haskell, а действия определяются и связываются вместе с операциями связывания.Кроме того, действие, которое ничего не делает, приводя к произвольному значению, может быть определено с помощью функции return
.
Обратите внимание, что привязка и возврат не являются специфическими для действий.Они могут использоваться с любым типом, который называет себя Монадой, чтобы делать всякие прикольные вещи.
Для пояснения рассмотрим readLn
.readLn
- это действие, которое в случае выполнения считывает строку из стандартного ввода и выдает ее проанализированное значение.Чтобы что-то сделать с этим значением, мы не можем сохранить его в переменной, потому что это нарушит ссылочную прозрачность :
a = readLn
Если бы это было разрешено, значение a зависело бы от мираи будет отличаться каждый раз, когда мы будем вызывать readLn
, то есть readLn
не будет ссылочно прозрачным.
Вместо этого мы привязываем действие readLn к функции, которая имеет дело с действием, получая новое действие,вот так:
readLn >>= (\x -> print (x + 1))
Результатом этого выражения является значение действия.Если Хаскелл встал с дивана и выполнил это действие, он прочитал бы целое число, увеличил его и распечатал.Связывая результат действия с функцией, которая что-то делает с результатом, мы сохраняем ссылочную прозрачность, играя в мире состояний.