2010-07-16 3 views
7

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

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

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

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

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

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

UPD2. Вы, ребята, говорите много интересного, но не отвечаете на мой вопрос. Я определил его более прямо сейчас. Извините за беспорядок с определением вопроса!

+1

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

+0

большое спасибо! это важно! – Halst

+0

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

ответ

0

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

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

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

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

+0

Кроме того, полная машина Turing имеет неограниченную рекурсию, поэтому функция может называть себя. –

2

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

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

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

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

+3

Примечание для читателя: действительно нет ничего мистического в отношении «Монады». Haskell не разрешает перегрузку в стиле C++; он использует классы типов. «Monad» - это всего лишь класс типа, под которым подписаны многие типы, поэтому они могут использовать красивые функции '>> =' и 'return'. Когда вы видите 'IO Int', просто подумайте о действии, которое, если оно было выполнено, дает Int. Вы используете оператор '>> =' (bind) для создания сложных действий, а не для написания инструкций, которые выполняются шаг за шагом. Оператор '>> =' используется для других типов по-фанки и интересным образом. Не бойтесь слова «М». –

+0

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

+1

@joey: спасибо, монады на 10% меньше страшны сейчас :-) – eruciform

3

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

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

Прежде всего, предположим, что вы взяли императивный язык, такой как 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)) 

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

+2

Я буквально LOLed на «Если Хаскелл сошел с дивана ...» В наши дни нынче ленивые языки. – Chuck

+0

Я читаю, что вы отвечаете примерно 10 раз, но все равно не можете получить - где происходит изменение состояния? какая функция должна была иметь состояния? Я все еще вижу только комбинационную логику – Halst

+0

, может быть, вы могли бы привести пример с синтаксисом? - если вы избегаете назначения переменных (за исключением возвращаемого значения функции) и сохраняете функции ссылочными прозрачными - не следует ли делать такой же трюк? – Halst

1

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

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

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

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

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

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

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

+0

В основе вашего ответа говорится то же самое, что я пытался объяснить в своем. –

5

Question: where is error in this reasoning?

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

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

+0

+1 Это утверждение согласуется с моим ответом –

Смежные вопросы