"Нормальним" способом формулювання того, що є чистою функцією , є терміни референційної прозорості . Функція є чистою, якщо вона є посилально прозорою .
Референційна прозорість , приблизно, означає, що ви можете замінити виклик функції її повернутим значенням або навпаки в будь-який момент програми, не змінюючи значення програми.
Так, наприклад, якби C printfбули відносно прозорими, ці дві програми мали б однакове значення:
printf("Hello");
і
5;
і всі наступні програми повинні мати однакове значення:
5 + 5;
printf("Hello") + 5;
printf("Hello") + printf("Hello");
Оскільки printfповертає кількість записаних символів, в даному випадку 5.
Це стає ще більш очевидним з voidфункціями. Якщо у мене є функція void foo, тоді
foo(bar, baz, quux);
має бути таким же, як
;
Тобто, оскільки fooнічого не повертає, я мав би змогу замінити це нічим, не змінюючи значення програми.
Тоді очевидно, що ні те, printfні fooінше не є посилально прозорими, а отже, жодне з них не є чистим. Насправді voidфункція ніколи не може бути референтно прозорою, якщо вона не є операцією.
Мені набагато легше впоратися з цим визначенням, як із тим, яке ви дали. Це також дозволяє застосовувати його за будь-якої деталізації: ви можете застосовувати його до окремих виразів, функцій та цілих програм. Це дозволяє, наприклад, говорити про таку функцію:
func fib(n):
return memo[n] if memo.has_key?(n)
return 1 if n <= 1
return memo[n] = fib(n-1) + fib(n-2)
Ми можемо проаналізувати вирази, що складають функцію, і легко зробити висновок, що вони не є посилально прозорими і, отже, не чистими, оскільки вони використовують змінну структуру даних, а саме memoмасив. Однак ми можемо також поглянути на функцію і побачити, що вона є посилально прозорою і, отже, чистою. Це іноді називають зовнішньою чистотою , тобто функцією, яка видається чистою для зовнішнього світу, але реалізується нечистою всередині.
Такі функції все ще корисні, оскільки, хоча домішка інфікує все навколо, зовнішній чистий інтерфейс створює своєрідний "бар'єр чистоти", де домішка заражає лише три лінії функції, але не витікає в іншу частину програми . Ці три рядки набагато легше проаналізувати на правильність, ніж всю програму.