Оскільки я грубо розумію модель заміщення (з референтною прозорістю (RT)), ви можете декомпонувати функцію в її найпростіші частини. Якщо вираз RT, то ви можете де-складати вираз і завжди отримувати однаковий результат.
Так, інтуїція цілком права. Ось кілька покажчиків, щоб отримати більш точні дані:
Як ви сказали, будь-який вираз RT повинен мати single
"результат". Тобто, даючи factorial(5)
вираз у програмі, він завжди повинен давати однаковий «результат». Отже, якщо певна factorial(5)
частина програми, і вона дає 120, вона завжди має 120, незалежно від того, який "порядок кроків" він розширюється / обчислюється - незалежно від часу .
Приклад: factorial
функція.
def factorial(n):
if n == 1:
return 1
return n * factorial(n - 1)
Є кілька міркувань щодо цього пояснення.
Перш за все, пам’ятайте, що різні моделі оцінювання (див. Прикладний та звичайний порядок) можуть давати різні «результати» для одного виразу RT.
def first(y, z):
return y
def second(x):
return second(x)
first(2, second(3)) # result depends on eval. model
У наведеному вище коді, first
і second
є референціально прозорими, і тим НЕ менш, вираз в кінці дає різні «результати» , якщо оцінені при нормальному порядку і аплікативного порядку ( в відповідності з останніми, вираз не зупиняється).
.... що призводить до використання "результату" в лапках. Оскільки для припинення виразу не потрібно, воно може не спричинити значення. Тож використання "результату" - це свого роду розмиття. Можна сказати, що вираз RT завжди computations
отримує те саме в моделі оцінки.
По-третє, може знадобитися побачити два програми, які foo(50)
з’являються в програмі в різних місцях, як різні вирази - кожен з яких дає свої власні результати, які можуть відрізнятися один від одного. Наприклад, якщо мова дозволяє динамічну область застосування, обидва вирази, хоча і лексично однакові, є різними. У перл:
sub foo {
my $x = shift;
return $x + $y; # y is dynamic scope var
}
sub a {
local $y = 10;
return &foo(50); # expanded to 60
}
sub b {
local $y = 20;
return &foo(50); # expanded to 70
}
Динамічний обсяг вводить в оману, оскільки він полегшує думці, що x
це єдиний внесок для foo
, коли насправді це є x
і є y
. Один із способів побачити різницю - перетворити програму в еквівалентну без динамічної області застосування - тобто, явно передаючи параметри, тому замість визначення foo(x)
ми визначаємо foo(x, y)
та передаємо y
явно в абонентах.
Справа в тому, що ми завжди function
налаштовані на думку: даючи певний вклад для виразу, нам дають відповідний "результат". Якщо ми даємо однаковий внесок, ми завжди повинні очікувати однакового "результату".
А що з наступним кодом?
def foo():
global y
y = y + 1
return y
y = 10
foo() # yields 11
foo() # yields 12
foo
Процедура ламає RT , тому що є перевизначення. Тобто ми визначилися y
в одному пункті, а в останньому - переозначили це саме y
. У прикладі perl, описаного вище, y
s є різними прив'язками, хоча вони мають однакову буквену назву "y". Тут y
фактично те саме. Ось чому ми кажемо (пере) призначення - це мета- операція: ви насправді змінюєте визначення своєї програми.
Приблизно люди зазвичай відображають різницю наступним чином: у вільній налаштуваннях для побічних ефектів ви маєте карту input -> output
. У "імперативній" обстановці у вас є input -> ouput
контекст, state
який може змінюватися з часом.
Тепер, замість того, щоб просто замінювати вирази на відповідні їм значення, також потрібно застосовувати перетворення до state
операції, яка вимагає цього (і, звичайно, вирази можуть звертатися до того ж, state
щоб виконати обчислення).
Отже, якщо у вільній програмі з побічними ефектами все, що нам потрібно знати, щоб обчислити вираз, - це його індивідуальний вхід, в імперативній програмі ми повинні знати вхідні дані та весь стан для кожного кроку обчислення. Обґрунтування - це перше, що зазнає великого удару (тепер, щоб налагодити проблематичну процедуру, вам потрібні введення та основний дамп). Деякі хитрощі є непрактичними, як запам'ятовування. Але також паралельність і паралелізм стають набагато складнішими.
RT
забороняє вас від використанняsubstitution model.
великої проблеми з тим, що не в змозі скористатисяsubstitution model
- це сила її використання для міркування про програму?