"Нормальним" способом формулювання того, що є чистою функцією , є терміни референційної прозорості . Функція є чистою, якщо вона є посилально прозорою .
Референційна прозорість , приблизно, означає, що ви можете замінити виклик функції її повернутим значенням або навпаки в будь-який момент програми, не змінюючи значення програми.
Так, наприклад, якби 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
масив. Однак ми можемо також поглянути на функцію і побачити, що вона є посилально прозорою і, отже, чистою. Це іноді називають зовнішньою чистотою , тобто функцією, яка видається чистою для зовнішнього світу, але реалізується нечистою всередині.
Такі функції все ще корисні, оскільки, хоча домішка інфікує все навколо, зовнішній чистий інтерфейс створює своєрідний "бар'єр чистоти", де домішка заражає лише три лінії функції, але не витікає в іншу частину програми . Ці три рядки набагато легше проаналізувати на правильність, ніж всю програму.