Обчисліть, якщо функція чиста


11

Відповідно до Вікіпедії:

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

Мені цікаво, чи можна записати функцію, яка обчислює, чи функція чиста чи ні. Приклад коду в Javascript:

function sum(a,b) {
    return a+b;
}

function say(x){
    console.log(x);
}

isPure(sum) // True
isPure(say) // False

7
Це може бути кандидатом на обмін стеком з інформатики . Це більше схиляється до сфери теорії ("можливої"), а не до практичної та дизайнерської ... Це трохи поза моїм кеном.

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

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

7
Неможливо обійтися без хакерських відбитків, характерних для платформи. Якщо функція - це чорна скринька, жоден експеримент не може довести, що вона чиста. Наприклад, якщо є щось подібне if (rand(1000000)<2) return WRONG_ANSWER, зондування функції багато разів для послідовної поведінки не допоможе. Але, якщо у вас є доступ до визначення функції, доказ тривіальний.
SK-логіка

1
@ user470365 З визначення чистої функції - "Оцінка результату не викликає жодних семантично помітних побічних ефектів чи результатів, таких як мутація змінних об'єктів або вихід на пристрої вводу / виводу". - Все, що пише в IO, є нечистим за визначенням. У прикладі, нечисті sayдзвінки console.logтакож sayє нечистими.

Відповіді:


17

Так, це можливо, залежно від мови.

У JavaScript ви можете визначити чи функція чиста за наступними критеріями:

  • Він зчитує лише параметри та місцеві жителі;

  • Це пишуть лише місцеві жителі;

  • Для не місцевих жителів він називає лише чисті функції;

  • Всі функції, які він викликає неявно, є чистими, наприклад toString; і

  • Він записує властивості місцевих жителів лише у тому випадку, якщо вони не псевдоніми немісцевих жителів.

Псевдонім не можна визначити в JavaScript в загальному випадку, оскільки ви завжди можете динамічно шукати властивості об'єкта ( object["property"]). Якщо ви ніколи цього не робите, і у вас є джерело всієї програми, я вважаю, що ця проблема простежується. Вам також знадобиться інформація про те, які нативні функції мають побічні ефекти, такі як console.logабо більшість, що стосується DOM.

Термін "чистий" також може використовувати деяке уточнення. Навіть у сильно, статично типово чисто функціональній мові програмування, де всі функції референтно прозорі, функція все одно не може припинитися. Отже, коли ми говоримо про id :: a -> aте, що ми говоримо насправді:

Враховуючи деяке значення типу a, функція idвиробляє значення типу a.

А точніше:

З огляду на деяке значення типу aфункція idробить НЕ виробляє значення , яке НЕ типу a.

Тому що дійсна реалізація idє error "Not implemented!". Як зазначає Петріс, ця нетотальність може розглядатися як різновид нечистоти. Koka - це функціональна мова програмування - із синтаксисом, змодельованим на JavaScript, - який може зробити можливі ефекти, такі як розбіжність (непереривання), прозорість референції, викидання винятків та дії вводу / виводу.


+1 - Враховуючи відповідь Петріса, було отримано стільки відгуків .....
mattnz

Я припускаю, що вам потрібно буде до списку критеріїв додати "Це викликає лише чисті функції".
Грег Хьюгілл

1
@GregHewgill: Хороший улов. Відповідно я оновив відповідь. Добре називати мутаційні функції місцевих жителів, якщо вони не є побічними ефектами. «Чистий» занадто перевантажений терміном…
Джон Перді

Вам також потрібно перевірити, чи toStringчисто для будь-якого об'єкта, який ви використовуєте як рядок.
Олег Вікторович Волков

Я не вважаю, що ця відповідь є правильною, тому що є лише підгрупа обставин, за якими можна зробити ці визначення. Поміркуйте: чи є ця функція чистою? function a (o) { return o.method(); }- ми не можемо відповісти на це, оскільки це залежить від того, який параметр oбуде передано. Крім того, ми не можемо пояснити, що відбувається, якщо попередньо сертифікована чиста функція буде змінена на нечисту реалізацію, яка завжди є потенційною проблемою з javascript.
Жуль

11

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

Розглянемо цю функцію:

function possiblyPure(x) {
    if (someCheck(x)) {
        return x+1; // pure code path
    }
    else {
        console.log("I'm so unpure..."); // unpure code path
    }
}

Очевидно, що якщо someCheckнечисте, то так і є possiblyPure. Але, якщо someCheckчисто і повертається trueза кожним можливим значенням x, possiblyPureце чисто, оскільки нечистий шлях коду недоступний!

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

EDIT: Доказ того, що це неможливо

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

Випадок А) Якщо чиста функція необхідна для завершення на кожен можливий вхід, ви повинні вирішити Проблему Зупинки , щоб визначити , є чи функція чиста. Оскільки це, як відомо, неможливо, за цим визначенням чистоту не можна обчислити.

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

function halts(f) {
   var fescaped = f.replace(/\"/g, '\\"');
   var upf = 'function() { '+f+'("'+fescaped+'\); console.log("unpure"); }';
   return isPure(upf);
}

Тепер isPureслід визначити, fзупиняється чи ні на власному джерелі в якості вхідного сигналу. Якщо вона зупиняється, upfнечиста; якщо він не припиняється, upfчистий iff fчистий.

Якби isPureпрацювали як очікувалося (повертає правильні результати та припиняється на кожному введенні), ми вирішили б проблему зупинки (*)! Оскільки це, як відомо, неможливо, isPureіснувати не може.

(*) для чистих функцій JavaScript, чого достатньо, щоб вирішити його і для машини turing.


3
Правда. Завжди можна зробити консервативний аналіз - перевірити, чи функція точно чиста, але неможливо перевірити, чи вона точно не є чистою.
SK-логіка

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

1

На це запитання про stackoverflow є відповідь yfeldblum, що є релевантною тут. (І у нього є потворне рішення, з якого я не можу зрозуміти. Чи було б поганим етикетом підняти щось, якому 3 роки?) Він дає доказ того, що чиста функція зводиться до проблеми зупинки в коментарі.

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

Отже, теоретично неможливо, практично можливо, якщо трохи підправити питання, і я думаю, наскільки це було б важко залежатиме від мови. Простішими / чистішими мовами з акцентом на незмінність та гарне відображення було б простіше.


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

0

Чудове запитання.

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

Але ти не можеш цього зробити взагалі. Можливо, програми, які не зупиняються, не є чистими, і ми не можемо вирішити проблему зупинки.


1
-1: Будь-що не тривіально написати функцію, яка проходить цей тест і є що-небудь, окрім чистого.
mattnz

3
За цією логікою будь-яка voidфункція була б "чистою", що явно хибно.
Грег Хьюгілл

1
@Greg: За розширенням, пустота foo (void) також повинна бути чистою.
mattnz

0

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


5
Працюючи назавжди, схоже, не знижує функція від відповідності його критеріям чистої функції.
whatsisname

+1: Існує неявна необхідність, щоб функція закінчувалась "Функція завжди оцінює одне й те саме значення результату ...."
mattnz

2
Послідовно працювати вічно без зміни будь-якого стану є ідеально "чистим". Але, звичайно, тут йдеться про термінологічне питання.
SK-логіка

@mattnz, така функція завжди буде оцінюватись за bottomзначенням.
SK-логіка

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