Чому сьогодні () є прикладом нечистої функції?


38

Схоже, читаючи щось подібне до цієї статті у Вікіпедії про "чисті функції" , вони подаються Today()як приклад нечистої функції, але мені це здається досить чистим. Це тому, що немає офіційного вводу аргументу? Чому фактичний час доби не трактується як "вхід у функцію"; у такому випадку, якщо ви давали йому один і той же вхід, тобто виконувались today()два рази за один і той же час, або проїжджали назад у часі, щоб виконати його знову (можливо, гіпотетично: )), вихід був би той самий час. Today()ніколи не дає вам випадкового числа. це завжди дає вам час доби.

У статті Вікіпедії сказано, що "в різні часи це дасть різні результати", але це означає, що якщо говорити про різні x sin(x), ви отримаєте різні співвідношення. І sin(x)є їх прикладом чистої функції.


8
Якби ти пройшов у той день, що б виконувала ця функція?
JB King

1
Я б очікував, що це дасть вам час доби. (не найкорисніша функція). Але в ньому немає жодного аргументу, який, на мою думку, є коренем відповіді.
Бред

3
Чи можете ви передбачити його вихід (виходячи з вхідних параметрів, які ви надали)?
Даніель Б

1
@DanielB Немає прогнозованої потужності для відсутнього / нульового вхідного параметра, виявляється. Єдине, що я можу зробити - це подивитися на наручні годинники (jk мій мобільний телефон).
Бред

"Чому фактичний час доби не трактується як" вхід до функції "" Це, в основному, проблема, яку монади намагаються вирішити. Чисті функції можуть базуватися лише на їх входах і не можуть мати побічних ефектів. Якщо ви зробите вклад "стан світу перед мною" та "стан світу після мене" частиною поверненої вартості та передайте ці стани світу через вашу програму, ви знову можете бути чистими.
Шон Мак-Що-небудь

Відповіді:


103

Це тому, що немає офіційного вхідного аргументу?

Це тому, що вихід залежить від чогось, що не є входом, а саме поточного часу.

Чому фактичний час доби не трактується як "вхід до функції"

Тому що ви не передали це як параметр. Якби ви передали це як параметр, функція стала би функцією ідентичності в датах, що є досить марним. Вся суть Today()функції полягає у виведенні чогось, що залежить від зовнішнього і постійно змінюваного значення (часу).

Перевага чистих функцій полягає в тому, що їх поведінка є абсолютно відтворюваною та детермінованою, що полегшує отримання формальних доказів та жорстких гарантій. Вони завжди роблять те саме. Today()майже навпаки: воно завжди (зважаючи на часову деталізацію) робить щось інше.


2
Отже, хоча час реальності є своєрідним входом, оскільки він не подається як вхід, і він знаходиться поза контролем функції (як внутрішньої функції, так і поза контролем того, хто дзвонить Today()) Today()стає нечистим. Ця Today()функція може бути трохи нерозумним прикладом. Більш доцільною може бути якась Count()функція. З огляду на однакову кількість предметів для підрахунку Count()завжди буде повертатися однакове число, але оскільки це не входить у сферу Count()його застосування, це нечисто.
Бред

1
@brad - це дещо сіра область - є неявний фактичний аргумент - масив чи список. З огляду на незмінний список та один і той же аргумент кожного разу, він завжди повертатиме те саме значення.
Макс

34
"час реальності є своєрідним вкладом" - так; Дійсно, глобальна держава неявно доступна (тобто "свого роду вхід") для всіх функцій, але якщо вони залежать від цього для їх результату, вони нечисті!
AakashM

4
@Brad count()на більшості мов програмування безумовно чистий. Він має явне вхідне значення: колекція, кількість яких ви хочете. Не плутати синтаксис типу myCollection.count(); це просто цукор для count(myCollection).
Андрес Ф.

Чудова відповідь, як завжди, але явно не охоплює незмінні вільні змінні. Вони не є входом до функції - не передаються як параметр - але функція залежить від них, навіть якщо вона все ще є референтно прозорою.

24

sin(x)завжди буде повертати одне і те ж значення, поки xзалишається однаковим. Today()може повернути різні результати з часом, оскільки це залежить від значень, що не знаходяться під вашим контролем . Наприклад, якщо щось поза контролем вашої програми змінить внутрішню систему під $current_datetime час роботи вашої програми, Today()раптом дасть різні результати.


"завжди поверне інше значення" - це трохи ... нечисте формулювання. Вікіпедія говорить, що "повертає поточний день тижня", тобто значення, отримані в понеділок, не будуть відрізнятися
gnat

7
@gnat: Правда, якщо щось зовнішнє для вашої програми не змінило внутрішній календар вашого комп'ютера, щоб раптом здалося, що це четвер. Тоді дзвінок Today()повернеться "четвер" у понеділок.
FrustratedWithFormsDesigner

3
@gnat Ну, це не завжди поверне інше значення (навряд чи є якась корисна функція). Але, як і більшість нечистих функцій, повернене значення може змінюватися навіть під час виконання однієї програми (наприклад, якщо вона працює протягом ночі).

3
@delnan: Так, це є нащадком наївних авторів сценаріїв баз даних! : P "Але ЯК міг пропустити 300 записів? Сценарій справно працював, коли я перевіряв його вчора вранці!"
FrustratedWithFormsDesigner

@delnan це точно. Я лише зазначив, що використання завжди в початковій редакції (виправлена ​​в поточній версії відповідь на міг ) було дещо неточним
gnat

13

Сьогодні () - це нечиста функція, оскільки її результат залежить від чогось, чого ви їй не надаєте; конкретно, поточний системний час. Тому його результат не є детермінованим, коли ґрунтується лише на входах, наданих при виклику.

Чиста функція була б int Add(int a, int b) {return a + b;}. Функція працює виключно з тим, що їй задано, і не використовує ніяких інших зовнішніх даних про стан. Природним результатом цього є те, що ви можете Add(2,2)отримати 4 з цього моменту до кінця часу. Крім того, оскільки функція не змінює жодного зовнішнього стану (у неї немає "побічних ефектів"), додавання () 2 і 2 з цього моменту до кінця часу не змінить нічого іншого в системі, якщо ви тоді призначити результат функції змінній або іншим чином використовувати значення для оновлення стану (що не є операцією, виконаною самою функцією). Практично всі класичні математичні операції є чистими функціями і можуть бути реалізовані як такі.

Сьогодні (), з іншого боку, може отримувати одне і те ж значення, коли дзвонять два рази поспіль, але не, якщо викликається повторно протягом декількох днів. Це відбувається тому, що це залежить від зовнішніх даних про стан, які не надані вами як параметр функції. Як результат, неможливо в межах програми контролювати результат функції Today (). Він видасть задане значення в даний день і ніколи не видасть це значення в будь-який інший день, якщо ви не зміните системний годинник комп'ютера, на якому він працює (зміна, як правило, відбувається за межами програми).

Нечиста функція не обов'язково є поганою справою; нечисті функції потрібні, навіть на функціональних мовах, для взаємодії з чим-небудь поза межами програми, наприклад, сховищами даних, трубопроводом зв'язку, дисплеями інтерфейсу, периферійними пристроями тощо. Програма, яка не робить жодного з цих речей, - це програма що різко обмежено у своїй корисності; Я б навіть пішов так далеко, щоб назвати таку програму тривіальною, оскільки без жодних засобів прийняти вклад чи будь-який проспект, щоб повідомити вам про її результати, це, можливо, нічого не робити. Програми, написані на функціональних мовах, можуть мати лише вхід, що надається під час виконання, і давати вихід, повідомлений під час виконання, без явно визначених нечистих методів, але це тому, що час виконання абстрагує всі ці нечисті деталі роботи в недосконалій комп'ютерній системі,

Просто дуже гарно знати, які функції, які ви використовуєте, є чистими, а які - ні, щоб ви могли добре приймати рішення про те, як вони використовуються. Нечисті функції, оскільки вони роблять речі або залежать від речей, які не видно з їх використання, можуть поводитись непередбачувано, даючи лише знання про використання. Подальше знання мети функції, а отже, чого вона потребує від зовнішнього стану, або необхідна для того, щоб перевести систему, яка використовує її, у послідовному стані і, таким чином, очікувати детермінованого результату.


8

Здається, досить очевидно, що ця функція не допомагає першому тесту на чистоту, даному на самому початку цієї сторінки:

  1. Функція завжди оцінює одне і те саме значення результату, задаючи однакові значення аргументів. Значення результату функції не може залежати від будь-якої прихованої інформації або стану, яка може змінюватися в ході виконання програми або між різними виконанням програми, а також не може залежати від зовнішнього вводу пристроїв вводу / виводу.

Зауважте, що оскільки він не бере аргументів, існує лише один можливий набір значень аргументів - порожній набір. І ця функція може і повертає різні результати для одних і тих же "значень (аргументів)".

Крім того, значення результату функції дійсно залежить від «прихованої ... стан , яке може змінюватися по мірі виконання програми триває». Тож черговий збій.


@ JörgWMittag Я не впевнений, де я стверджую, що функція без аргументів не може повернути значення.
AakashM

Мозковий пердеть. Я читав "існує лише один можливий набір повернених значень".
Йорг W Міттаг

8

() => 1була б чистою функцією, оскільки вона завжди повертає 1. Today()може повернути "понеділок" або "вівторок" або майже будь-яке інше значення.

Ще один спосіб подумати про це - чисті функції не залежать від стану. Світ зазвичай вважається державним. Вам потрібно знати стан реальності, щоб знати, який сьогодні день.

Однак вам не потрібно знати нічого особливого про стан світу, щоб знати, що sin(x)таке. І коли-небудь заклик до sin(x)даного xповерне те саме значення.


У Вікіпедії сказано, що "повертає поточний день тижня", це означає, що він може повернутися в понеділок, вівторок тощо, але не "23.01.2013" і "24.01.2013"
gnat

7
@gnat: Оновлено, але різниця насправді не була суттєвою.
Гуванте

2

Date(timestamp)була б чистою функцією. Через свою ідентичність. І тому, що побічних ефектів не було б.

Today()може змінювати його результат залежно від того, коли ви його зателефонували. Саме це робить його нечистим. Це не бездумно. Він не має побічних ефектів, але це не робить його чистим.


2

Ось невеликий псевдо-код, про який я думаю, обговорюючи чисті функції

newValue = Function();
while(true)
{
   oldValue = newValue;
   newValue = Function();
   assert( newValue == oldValue );
}

Якщо це працює нескінченно і ніколи не може викликати ствердження, це чиста функція. Тим більше, якщо у вас є функція, яка використовує аргументи, то невелика модифікація ....

oldValue = Function( importantVariableToYourApp );
newValue = Function( importantVariableToYourApp );
assert( newValue == oldValue );

Якщо ви можете використовувати це після кожного призначення змінної у вашому додатку, і це не змінює результатів у вашому додатку, і він ніколи не може зірвати ствердження, то це чиста функція.


2

По-перше, немає такої функції, як функція без аргументу (або масив без індексів або карта без ключів). Це визначальна характеристика функції для зіставлення одного або декількох значень аргументу на інше значення.

Отже, todayце взагалі не функція, отже, чиста функція. Або ми можемо інтерпретувати синтаксис

today()

трохи, щоб це означало

today   ()      -- today, applied to the value ()

Наприклад, у Haskell це було б дійсно:

data Day = Mon | Tue | Wed | Thu | Fri | Sat | Sun deriving Show
today :: () -> Day
today () = ....?
main = print (today())

тому що існує тип () з одним значенням ().

Питання лише в тому, як можна todayобчислити день тижня, якщо він має лише ()? Це просто неможливо без зчитування системного таймера, безпосередньо чи через допоміжні нечисті функції.

Системний таймер є прекрасним прикладом для глобального стану.


1

Проблема today()полягає в тому, що він може дати інший результат, якщо його викликають два чи більше разів у функції.

Ось приклад коду, який може ввести помилку.

function doSomething(when)
{
     if(today() == when)
     {
           // open a resource or create a temp file.....
     }

     // do some other work

     if(today() == when)
     {
           // close the resource or delete temp file.....
     }
}

Це можливо у наведеному вище прикладі. Що друге ifтвердження не буде виконано. Навіть якщо перший зробив. Залишаючи ресурс у поганому стані.


1

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

Кожен раз, коли ми дзвонимо Today(), ми надаємо йому однакові параметри (жодні), але не обов'язково отримуємо однаковий результат (понеділок, вівторок тощо).


4
це, здається, просто повторює пункт, зроблений і пояснений у верхній відповіді , опублікованій близько двох років тому. Навряд чи варто стикатися з дворічним запитанням із таким вмістом
gnat

1
Я не надто знайомий з тим, як працює stackexchange, але я подумав, що оскільки це стосується найважливіших питань, про це вже стикалися. Що стосується повторення, я пам’ятаю, що читав на мета, що може бути корисним кілька подібних відповідей. Я відчуваю, що моє є лаконічним і потенційно корисним.
Зантієр
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.