Пропратни ефекти

Из Википедије, слободне енциклопедије
Иди на навигацију Иди на претрагу


У информатици и рачунарству, за потпрограм или израз кажемо да има пропратни ефекат ако мења неко стање или има приметну интеракцију са позивајућом функцијом. На пример, одређена функција може да модификује глобалне променљиве или локалне променљиве, неки од аргумената, диже изузетак, уписује податке у датотеку или на стандардни излаз, чита податке, или позове другу функцију која има пропратни ефекат. Када постоје пропратни ефекти, понашање програма може да зависи од редоследа евалуације. Разумевање и дебаговање функције са пропратним ефектима захтева знање о контексту и могућим редоследом позивања функција.[1][2]

Пропратни ефекти су најчешћи начин на који програм комуницира са спољним светом (људима, системским фајловима, другим рачунарима на мрежи). Степен коришћености пропратних ефеката зависи од програмске парадигме. Императивно програмирање је познато по честом коришћењу пропратних ефеката.

У функционалном програмирању, пропратни ефекти се ретко користе. Недостатак пропратних ефеката чини их лакшим за верификацију програма. Функционални језици као Стандард МЛ, Scheme и Скала их не забрањују, али је обично на програмерима да их избегавају.[3] Функционални језик Хаскел изражава пропратне ефекте као што су Улаз/Излаз и друга израчунавања са стањима користећи монадичне акције.[4][5]

Асемблер програмери морају да пазе на скривене пропратне ефекте — инструкције које модификују део процесорских стања која нису споменута у инструкцијској мнемоници. Класичан пример скривеног пропратног ефекта је аритметичка инструкција која имплицитно модификује стање регистра (скривени пропратни ефекат) док експлицитно модификује регистар (отворен ефекат). Једна могућа мана скупа инструкција са скривеним пропратним ефектима је то што, ако више инструкција има пропратне ефекте на једном стању, као стања регистара, онда логика потребна за ажурирање тог стања редом може постати уско грло. Проблем је посебно изражен на неким процесорима дизајнираним пајплајнингом (од 1990) или ванредним извршавањем. Такви процесори могу да захтевају додатну контролу кола да би открили скривене пропратне ефекте и зауставили пајплајн ако следећа инструкција зависи од резултата ових ефеката.

Референтна транспарентност[уреди]

Одсуство пропратних ефеката је неопходан, али не и довољан услов за референтну транспарентност. Референтна транспарентност значи да израз (као што је функцијски позив) може бити замењен његовом вредношћу; ово захтева да израз нема пропратне ефекте и да буде чист (увек враћа исти резултат за исти унос).

Привремени пропратни ефекти[уреди]

Пропратни ефекти проузроковани временом потребним за извршавање операције су обично игнорисани када се говори о пропратним ефектима и референтој транспарентности. Има случајева где су операције убачене баш због њихових привремених пропратних ефеката нпр. Sleep(5000) или for(int i=0; i < 10000; i++){}. Ове инструкције не мењају стање сем времена за њихово извршавање.

Идемпотенција[уреди]

За функцију са пропратним ефектима се каже да је идемпотентна под секвенцијалном композицијом (f; f) ако, када је позвана са истим аргументом двапут, други позив враћа исту вредност и нема пропратне ефекте који га могу разликовати од првог позива. На пример, размотримо:

x = 0;
def xSetter(n):
    global x
    x = n
xSetter(5)
xSetter(5)

Овде, xSetter је идемпотентан зато што други позив xSetter (са истим аргументом) враћа исту вредност и не мења видљиво стање програма. Приметимо да је ово различито од идемпотенције под композицијом функција (f ∘ f): xSetter није идемпотентан под композицијом функција јер xSetter(5) и xSetter(xSetter(5)) постављају x на различите вредности где повратна вредност xSetter јесте x; у овом примеру повратна вредност је увек 5.

Пример[уреди]

Честа демонстрација понашања пропратних ефеката је оператор доделе у програмском језику C++. На пример, наредба додела враћа десни операнд и има пропратни ефекат доделе те вредности променљивој. Ово омогућава синтаксички чисту вишеструку доделу:

int i, j;
i = j = 3;

Пошто је оператор доделе десно асоцијативан, ово је еквивалентно са

int i, j;
i = (j = 3); // j = 3 враћа 3, који се затим додељује променљивој i

Где је резултат додељивање вредности 3 изразу "j" који добија вредност променљиве "i". Ово представља потенцијални проблем за програмере почетнике који могу да грешком замене

while (b == 10) {} // Испитује да ли је b једнако 10

са

// Функција доделе враћа 10
// које се аутоматски кастује на "true"
// па се петља никад не завршава
while (b = 10) {}


Референце[уреди]

  1. ^ “Research Topics in Functional Programming” ed. D. Turner, Addison-Wesley, (1990). стр. 17–42. Retrieved from: Hughes, John, Why Functional Programming Matters (PDF) 
  2. ^ Collberg, CSc 520 Principles of Programming Languages, Department of Computer Science, University of Arizona 
  3. ^ Matthias Felleisen et al., How To Design Programs, MIT Press
  4. ^ Haskell 98 report, http://www.haskell.org.
  5. ^ Imperative Functional Programming, Simon Peyton Jones and Phil Wadler, Conference Record of the 20th Annual ACM Symposium on Principles of Programming Languages, pages 71—84, 1993