Редактировать: Хотя я, по-видимому, пропустил яблочко по актуальному вопросу, я думаю, что мой ответ довольно хорош, поэтому я сохраняю его :-) (см. Ниже).
Я предполагаю, что более кратким способом фразы может быть вопрос: может ли чисто функциональный язык вычислить все, что необходимо для императива?
Прежде всего, предположим, что вы взяли императивный язык, такой как 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, чисто функциональный язык. Строго говоря, у Haskell нет оператора «присваивания». Например:
my_sum numbers = ??? where
i = 0
total = 0
Здесь вы не можете написать «цикл цикла», который увеличивает i и тотал, когда он идет. Однако все не потеряно. Просто использовать рекурсию, чтобы получать новые 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 является действием IO, выполняемым Haskell, и действия определяются и связаны вместе с операциями связывания. Кроме того, действие, которое ничего не делает, дающее произвольное значение, может быть определено с помощью функции return
.
Обратите внимание, что привязка и возврат не относятся к действиям. Они могут использоваться с любым типом, который называет себя Монадой, чтобы делать всевозможные напуганные вещи.
Чтобы уточнить, рассмотрите readLn
. readLn
- это действие, которое, если оно выполняется, будет читать строку со стандартного ввода и выводит ее анализируемое значение.Для того, чтобы сделать что-то с этим значением, мы не можем хранить его в переменной, потому что нарушило бы ссылочную прозрачность:
a = readLn
Если бы это было разрешено, значение а будет зависеть от мира и будет каждый раз разные мы назвали readLn
, что означает, что readLn
не будет ссылочно прозрачным.
Вместо этого мы связываем действие ReadLn к функции, которая имеет дело с действием, что дает новое действие, например, так:
readLn >>= (\x -> print (x + 1))
Результат этого выражения является значение действия. Если Хаскелл сошел с кушетки и выполнил это действие, он прочитал бы целое число, увеличил его и распечатал. Связывая результат действия с функцией, которая что-то делает с результатом, мы получаем, чтобы поддерживать ссылочную прозрачность во время игры в мире состояния.
«это означает, что с чистым функциональным языком ... можно описать только последовательную логику» - разве вы не имеете в виду «комбинационную логику»? –
большое спасибо! это важно! – Halst
Не могли бы вы объяснить, почему утверждение «чистый функциональный язык может описывать только комбинационную логику» неверно? Спасибо. –