Чи функція негайно нечиста, якщо вона приймає функцію як параметр?


17

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

Пов’язано: якщо функція застосовує чисту функцію, яка визначена поза функцією, але не передається як параметр, чи вона все ще чиста, якщо вона відповідає критеріям відсутності побічних ефектів, і вихід залежить тільки від введення?

Для контексту я пишу функціональний код у JavaScript.


В якості тривіального зустрічного прикладу розгляньте:foo = function(function bar){ print(bar.toString()) }
Девід каже: Поновіть Моніку

1
@DavidGrinberg Я думаю, що це не протилежний приклад, і насправді висвітлює більшу проблему; якщо у вас є функції, які можна відміняти, і які не можуть гарантувати, що реалізація не має побічних ефектів, то ви не можете гарантувати, що більшість функцій, які приймають об'єкти і викликають їхні методи, є чистими. Можливо, bar's toString () видаляє деякі файли з диска?
Джошуа Тейлор

3
@DavidGrinberg Але, я думаю, ти думаєш у хорошому напрямку. foo = function(function bar) { return 3; } є чистою і приймає функцію як аргумент.
Джошуа Тейлор

@JoshuaTaylor Справедливий момент, я про це не думав. Але ви вже по суті вирішили питання. Як альтернативне виправлення, просто зателефонуйте «root» toString()(тобто той, який ви знайдете у Object Java).
Девід каже: Відновіть Моніку

Відповіді:


22

Поки всі значення, використовувані у функції, визначаються виключно її параметрами, це чиста функція.

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

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

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

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


Що стосується вашого твердження, що "доки всі значення, які використовуються у функції, визначаються виключно за її параметрами, це чиста функція". Що відбувається у випадку констант? Якщо у мене є функція areaOfCircle r => Math.Pi * r * r, чи буде areaOfCircleнечистою, оскільки вона не використовує лише параметри?
Девід Арно

2
@DavidArno Це справедливо. Згідно з референтною прозорістю, посилання на статичну зовнішню величину не відрізнятиметься від того, щоб вона була жорстко закодована, тому вона все одно була б чистою.
Daenyth

1
"це означає, що можна зробити чисту функцію нечистою поведінкою" - за визначенням, чиста функція не може мати нечисту поведінку. Ви робите помилку, думаючи, що функція, f(f2)яка викликає f2, не транзитивно покладається на те, на що f2покладається. Функція, яка може викликати довільні передані функції, не є чистою.
user2357112 підтримує Моніку

2
@Daenyth: Краще, але все ж передбачається, що функція повинна викликати функцію, що передається. Це може бути щось на зразок function compose(f, g) {return function h(x) {return f(g(x));};}, що є чистим, незважаючи на те, що функції беруть аргументи.
user2357112 підтримує Моніку

1
"Мені здається, що нечисті функції використовуються як аргументи функції для чистих функцій." - не функціональна мова, але деякі функції бібліотеки C ++ мають специфічні попередження, що аргументи предиката повинні бути (деяким наближенням до) чистими. Отже, в одному сенсі це означає, що це не тільки рідко, це ніколи справедливо не відбувається. Але в іншому розумінні факт, який вони повинні заборонити, це тому, що люди іноді хочуть це робити. Наприклад, вони хочуть передати findрутину нечистому предикату, який повертає "true" для третього відповідного елемента, який він стикається, або якоїсь такої дурниці.
Стів Джессоп

19

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

№ Контрприклад:

function pure(other_function) {
    return 1;
}

Не має значення, чи буде other_function є це чиста функція, чиста функція чи взагалі не функція. pureФункція є чистою.

Інший контрприклад:

function identity(x) {
    return x;
}

Ця функція є чистою, навіть якщо xце нечиста функція. identity(impure_function)завжди повернеться impure_function, незалежно від того, скільки разів ви повторите дзвінок. Не має значення, чи identity(impure_function)()завжди повертає одне й те саме; повернене значення функції, що повертається, не впливає на її чистоту.


Взагалі, якщо функція може викликати функцію, вона була передана як аргумент, вона не є чистою. Наприклад, функція function call(f) {f();}не є чистою, оскільки, хоча вона не згадує про будь-який глобальний або змінний стан, fможе бути щось подібне, alertщо викликає видимі побічні ефекти.

Якщо функція приймає функції як аргументи, але вона не викликає їх і не викликає їх виклик, то вона може бути чистою. Це все ще може бути нечистим, якщо він робить якусь іншу нечисту річ. Наприклад, function f(ignored_function) {alert('This isn't pure.');}нечистий, хоча він ніколи не дзвонить ignored_function.


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

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

12

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

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

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

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

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


5

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

Це не гіпотетично, дійсно є хороші способи гарантувати це. Принаймні сильно набраною мовою.

Таку чисту функцію ~ ви б написали в JavaScript

function foo(f) {
   return f(1) + 2;
}

можна перекласти безпосередньо на Haskell:

foo :: (Int -> Int) -> Int
foo f = f 1 + 2

Тепер у JavaScript ви можете робити такі злі речі

js> foo (function(x) {console.log("muharhar"); return 0})
muharhar
2

У Haskell це неможливо . Причина - щось подібне до побічних ефектів console.log()завжди повинно мати тип результату IO something, а не лише somethingпоодинці.

GHCi> foo (\x -> print "muarhar" >> return 0)

<interactive>:7:12:
    Couldn't match expected type ‘Int’ with actual type ‘IO b0’
    In the expression: print "muarhar" >> return 0
    In the first argument of ‘foo’, namely
      ‘(\ x -> print "muarhar" >> return 0)’
    In the expression: foo (\ x -> print "muarhar" >> return 0)

Щоб цей вираз було встановлено перевірку, нам потрібно дати fooпідпис типу

foo :: (Int -> IO Int) -> Int

Але виявляється, я вже не можу його реалізувати: оскільки функція аргументу має IOрезультат, я не можу використовувати її всередині foo.

<interactive>:8:44:
    Couldn't match expected type ‘Int’ with actual type ‘IO Int’
    In the first argument of ‘(+)’, namely ‘f 1’
    In the expression: f 1 + 2

Єдиний спосіб, в якому я міг би використати IOдію, fooце якщо результат fooмає тип " IO Intсам":

foo :: (Int -> IO Int) -> IO Int
foo f = do
   f1 <- f 1
   return (f1 + 2)

Але на даний момент з підпису видно, fooщо це теж не чиста функція.


1
Перш ніж сказати "неможливо", подивіться на unsafeIO:-)
Бергі

2
@Bergi: це насправді не частина Haskell, а його зовнішній інтерфейс функцій: щоб дозволити стверджувати, що функція, визначена якоюсь іншою мовою, є чистою, що компілятор Haskell, очевидно, не може зробити висновок з підпису типу, оскільки інші мови, як правило, не мають така штука як IO. Між іншим, він також може бути використаний для заподіяння хаосу, приховуючи побічні ефекти в "чистій" функції, але це справді небезпечно в Haskell, оскільки насправді не існує надійного способу визначення порядку оцінки чистих функцій.
Ліворуч

Так, це правда. Однак, я думаю, я бачив, що він використовувався для "приховування" корисних побічних ефектів і в "чистій" функції, де безпека підходу повинна була бути встановлена ​​раніше.
Бергі

@Bergi Ви в основному не повинні користуватися unsafeIO; це люк для втечі в останню чергу, який убік гарантує систему типу, а отже, ваш не гарний момент.
Андрес Ф.

0

Ні, це не.

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

Чисте / нечисте відношення трохи схоже на синхронізацію / асинхронізацію в JS. Ви можете вільно використовувати чистий код від нечистого, але не навпаки.


Ця відповідь не додає нічого, що в цьому вже не було пояснено ... Будь ласка, перегляньте попередні відповіді, перш ніж перезавантажувати речі :)
Андрес Ф.

Що з аналогією синхронізації / асинхронізації?
Боббі Марінофф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.