понимание ссылочной прозрачности

вообще, у меня болит голова, потому что что-то не так с моими рассуждениями:

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

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

  3. Это делает логику таких функций is комбинационный (в отличие от последовательного)

  4. Это означает, что с чистым функциональным языком (который имеет только функции rt) можно описать только комбинационную логику.

последнее утверждение выводится из этого рассуждения,но это очевидно ложно; это означает, что есть ошибка в рассуждениях. [вопрос: где ошибка в этих рассуждениях?]

UPD2. Вы, ребята, говорите много интересный материал, но не ответ на мой вопрос. Теперь я определил это более определенно. Извините за путаницу с определением вопроса!

5 ответов


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

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

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

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


вопрос: где ошибка в этих рассуждениях?

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

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


Edit: хотя я, по-видимому, пропустил яблочко в фактическом вопросе, я думаю, что мой ответ довольно хорош, поэтому я держу его :-) (см. ниже).

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

прежде всего, предположим, что вы взяли императивный язык, такой как 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, как это происходит вдоль. Однако не все потеряно. Просто используйте рекурсию, чтобы продолжать получать новые is и totals:

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-это действие ввода-вывода, которое выполняет Haskell, а действия определяются и связываются вместе с операциями привязки. Кроме того, действие, которое ничего не делает, давая произвольное значение, может быть определено с помощью


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

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

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

Я действительно не знаю о вопросе таблицы правды.


вот мой удар в ответ на вопрос:

любая система может быть описана как комбинаторная функция, большая или малая.

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

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

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

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

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