Procedurální parametr - Procedural parameter - Wikipedia
v výpočetní, a procedurální parametr je parametr a postup to je sám o sobě postup.
Tento koncept je mimořádně výkonný a všestranný programování nástroj, protože umožňuje programátorům upravit určité kroky a knihovní procedura svévolně komplikovanými způsoby, aniž byste museli rozumět nebo upravovat kód tohoto postupu.
Tento nástroj je zvláště efektivní a pohodlný v jazycích, které podporují definice místních funkcí, jako Pascal a moderní GNU dialekt z C. Je to ještě více, když funkční uzávěry jsou dostupné. Stejnou funkčnost (a další) poskytuje předměty v objektově orientovaný programovací jazyky, ale za výrazně vyšší cenu.
Procedurální parametry do jisté míry souvisejí s pojmy prvotřídní funkce a anonymní funkce, ale je od nich odlišný. Tyto dva koncepty mají více společného s tím, jak jsou definovány funkce, než s tím, jak jsou používány.
Základní koncept
Ve většině jazyků, které tuto funkci poskytují, je to procedurální parametr F podprogramu P lze volat uvnitř těla P jako by to byl běžný postup:
postup P(F): vrátit se F(6,3) * F(2,1)
Při volání podprogramu P, jeden mu musí dát jeden argument, kterým musí být nějaká dříve definovaná funkce kompatibilní s tímto způsobem P používá svůj parametr F. Například pokud definujeme
postup Plus(X, y): vrátit se X + y
pak můžeme zavolat P (Plus) a výsledek bude Plus(6,3) * Plus(2,1) = (6 + 3) * (2 + 1) = 27. Na druhou stranu, pokud definujeme
postup cit(u, proti): vrátit se u/proti
pak hovor P (cit) vrátí se cit(6,3)*cit(2,1) = (6/3) * (2/1) = 4. Nakonec definujeme
postup zlo(z) vrátit se z + 100
pak hovor P (zlo) nebude mít velký smysl a může být označen jako chyba.
Syntaktické detaily
Některé programovací jazyky, které mají tuto funkci, mohou povolit nebo vyžadovat úplnou deklaraci typu pro každý procedurální parametr F, včetně počtu a typu jeho argumentů a typu jeho výsledku, pokud existují. Například v programovacím jazyce C může být výše uvedený příklad napsán jako
int P(int (*F)(int A, int b)) { vrátit se F(6,3) * F(2,1);}
V zásadě skutečná funkce jednat to je předáno jako argument, když P je volána, musí být typově kompatibilní s deklarovaným typem parametru procedury F. To obvykle znamená jednat a F musí vrátit stejný typ výsledku, musí mít stejný počet argumentů a odpovídající argumenty musí mít stejný typ. Názvy argumentů však nemusí být stejné, jak ukazuje Plus a cit příklady výše. Některé programovací jazyky však mohou být v tomto ohledu přísnější nebo liberálnější.
Scoping
V jazycích, které umožňují procedurální parametry, jsou pravidla určování rozsahu obvykle definována tak, že procedurální parametry jsou prováděny v jejich nativním rozsahu. Přesněji předpokládejme, že funkce jednat je předán jako argument P, jako jeho procedurální parametr F; a F je poté volána zevnitř těla P. Zatímco jednat je prováděn, vidí prostředí jeho definice.[potřebný příklad ]
Implementace těchto pravidel pro stanovení rozsahu není triviální. Do té doby jednat je nakonec proveden, aktivační záznamy kde jeho proměnné prostředí žijí, mohou být libovolně hluboko v zásobníku. Jedná se o tzv dolů funarg problém.
Příklad: Obecný druh vložení
Koncept procedurálních parametrů lze nejlépe vysvětlit na příkladech. Typickou aplikací je následující obecná implementace třídění vložení algoritmus, který vyžaduje dva celočíselné parametry A,b a dva procedurální parametry prec, vyměnit:
postup Isort(A, b, prec, vyměnit): celé číslo i, j; i ← A; zatímco i ≤ b dělat j ← i; zatímco j > A a prec(j, j−1) dělat vyměnit(j, j−1); j ← j−1; i ← i+1;
Tento postup lze použít k řazení prvků X[A] přes X[b] nějakého pole X, svévolně typ v pořadí určeném uživatelem. Parametry prec a vyměnit by měly být dva funkce, definovaný klient, oba berou dvě celá čísla r, s mezi A a b. The prec funkce by se měla vrátit skutečný pouze tehdy, pokud jsou data uložena v systému Windows X[r] by mělo předcházet datům uloženým v X[s], v objednávce definovaném klientem. The vyměnit funkce by měla vyměnit obsah X[r] a X[s] a nevrátí žádný výsledek.
Správným výběrem funkcí prec a vyměnit, stejný Isort postup lze použít k přeuspořádání polí libovolného datového typu, uložených na jakémkoli médiu a uspořádaných v jakékoli datové struktuře, která poskytuje indexovaný přístup k jednotlivým prvkům pole. (Všimněte si však, že existují třídicí algoritmy které jsou mnohem efektivnější než třídění vkládání pro velká pole.)
Třídění čísel s plovoucí desetinnou čárkou
Například můžeme řadit pole z 20 čísel s plovoucí desetinnou čárkou, z[1] až z[20] v rostoucím pořadí voláním Isort (1, 20,zprec,zswap), kde jsou funkce zprec a zswap jsou definovány jako
postup zprec(r, s): vrátit se (z[r] < z[s]);postup zswap(r, s): plovák t; t ← z[r]; z[r] ← z[s]; z[s] ← t
Řazení řádků matice
Pro další příklad, pojďme M být matice celých čísel s 10 řádky a 20 sloupci, přičemž indexy začínají na 1. Následující kód změní uspořádání prvků v každém řádku tak, aby všechny sudé hodnoty byly před všemi lichými hodnotami:
celé číslo ipostup eoprec(r, s): vrátit se (M[i, r] mod 2) < (M[i, s] mod 2);postup eoswap(r, s): celé číslo t; t ← M[i,r]; M[i,r] ← M[i,s]; M[i,s] ← t;pro i od 1 na 10 dělat Isort(1, 20, eoprec, eoswap);
Všimněte si, že účinky eoprec a eoswap závisí na čísle řádku i, ale Isort postup to nemusí vědět.
Postup vektorového třídění
Následující příklad používá Isort definovat postup vecsort to trvá celé číslo n a celočíselný vektor proti s prvky proti[0] až proti[n−1] a seřadí je podle rostoucího nebo sestupného pořadí podle toho, zda jde o třetí parametr přírůstek je skutečný nebo Nepravdivé, respektive:
postup vecsort(n, proti, přírůstek): postup vprec(r, s): -li přírůstek pak vrátit se proti[r] < proti[s]; jiný vrátit se proti[r] > proti[s]; postup vswap(r, s): celé číslo t; t ← proti[r]; proti[r] ← proti[s]; proti[s] ← t Isort(0, n−1, vprec, vswap);
Všimněte si použití definic vnořených funkcí k získání funkce vprec jehož účinek závisí na parametru přírůstek přešel na vecsort. V jazycích, které neumožňují definice vnořených funkcí, jako je standardní C, by získání tohoto efektu vyžadovalo poměrně komplikované a / nebo nebezpečný pro vlákna kód.
Příklad: sloučení dvou sekvencí
Následující příklad ilustruje použití procedurálních parametrů ke zpracování abstraktních datových struktur nezávisle na jejich konkrétní implementaci. Problémem je sloučit dvě seřazené sekvence záznamů do jedné seřazené sekvence, kde si klient může zvolit povahu záznamů a kritérium řazení. Následující implementace předpokládá pouze to, že na každý záznam lze odkazovat pomocí adresy paměti a existuje „nulová adresa“ Λ, která není adresou žádného platného záznamu. Klient musí uvést adresy A, B prvních záznamů v každé sekvenci a funkcí prec, další, a připojit, bude popsáno později.
postup spojit(A, B, prec, dalšíA, dodatekA, další B., appendB): adresa ini, ploutev, t ini ← Λ; ploutev ← Λ zatímco A ≠ Λ nebo B ≠ Λ dělat -li B = Λ nebo (A ≠ Λ a B ≠ Λ a prec(A, B)) pak t ← dalšíA(A) ploutev ← dodatekA (A, ploutev); -li ini = Λ pak ini ← ploutev A ← t jiný t ← další B.(B) ploutev ← appendB(B, ploutev); -li ini = Λ pak ini ← ploutev B ← t vrátit se ini
Funkce prec by měl vzít adresy r, s dvou záznamů, jeden z každé sekvence, a vrátit se skutečný pokud by první záznam měl přijít před druhým ve výstupní sekvenci. Funkce dalšíA by měl vzít adresu záznamu z první sekvence a vrátit adresu dalšího záznamu ve stejné sekvenci, nebo Λ, pokud žádný není. Funkce dodatekA by měl připojit první záznam ze sekvence A do výstupní sekvence; jeho argumenty jsou adresa A záznamu, který má být připojen, a adresu ploutev posledního záznamu výstupního seznamu (nebo Λ, pokud je tento seznam stále prázdný). Postup dodatekA by měl vrátit aktualizovanou adresu posledního prvku výstupního seznamu. Postupy další B. a appendB jsou analogické pro ostatní vstupní sekvence.
Sloučení propojených seznamů
Pro ilustraci použití obecného postupu slučování je zde kód pro sloučení dvou jednoduchých propojené seznamy, počínaje uzly na adresách R, S. Zde předpokládáme, že každý záznam X obsahuje celé číslo pole X.INFO a pole adresy X.DALŠÍ který ukazuje na další uzel; Kde informace pole jsou v každém seznamu v rostoucím pořadí. Vstupní seznamy jsou demontovány sloučením a jejich uzly se používají k sestavení výstupního seznamu.
postup listmerge(R, S): postup prec(r, s): vrátit se r.INFO < s.INFO postup další(X): vrátit se X.DALŠÍ postup připojit(X, ploutev) -li ploutev ≠ Λ pak ploutev.DALŠÍ ← X X.DALŠÍ ← Λ vrátit se X vrátit se spojit(R, S, prec, další, připojit, další, připojit)
Sloučení vektorů
Následující kód ilustruje nezávislost obecného spojit postup od skutečného znázornění sekvencí. Spojuje prvky dvou běžných polí U[0] až U[m-1] a PROTI[0] až PROTI[n−1] čísel s plovoucí desetinnou čárkou, v sestupném pořadí. Vstupní pole se nemění a sloučená posloupnost hodnot se uloží do třetího vektoru Ž[0] až Ž[m+n-1]. Stejně jako v programovacím jazyce C předpokládáme, že výraz „&PROTI"získá adresu proměnné PROTI, "*str"získá proměnnou, jejíž adresa je hodnotou str, a to „& (X[i]) „je ekvivalentní s„ & (X[0]) + i"pro jakékoli pole X a jakékoli celé číslo i.
postup arraymerge(U, m, PROTI, n, Ž): postup prec(r, s): vrátit se (*r) > (*s) postup nextU(X): -li X = &(U[m−1]) pak vrátit se Λ jiný vrátit se X + 1 postup nextV(X): -li X = &(PROTI[n−1]) pak vrátit se Λ jiný vrátit se X + 1 postup připojit(X, ploutev) -li ploutev = Λ pak ploutev ← &(Ž[0]) (*ploutev) ← (*X) vrátit se ploutev + 1 -li m = 0 tedy U ← Λ -li n = 0 tedy PROTI ← Λ vrátit se spojit(U, PROTI, prec, nextU, připojit, nextV, připojit)
Příklad: Určitý integrál
Integrace v intervalu
Následující postup vypočítá přibližnou hodnotu integrální F (X) dX dané skutečné hodnoty funkce F v daném intervalu [A,b] z skutečná linie. The numerická metoda používá se lichoběžníkové pravidlo s daným číslem n kroků; reálná čísla jsou aproximována čísly s plovoucí desetinnou čárkou.
postup Intg(F, A, b, n): plovák t, X, s; celé číslo i -li b = A pak vrátit se 0 X ← A; s ← F(A) / 2; pro i z 1 na n−1 dělat t ← i/(n+1); X ← (1−t) * A + t * b; s ← s + F(X) s ← F(b) / 2 vrátit se (b − A) * s / n
Integrace přes disk
Zvažte nyní problém integrace dané funkce G, se dvěma argumenty, přes disk D s daným středem (xc,yc) a daný poloměr R. Tento problém lze změnit na dva vnořené integrály s jednou proměnnou změnou proměnných
Následující kód implementuje vzorec na pravé straně:
postup DiskIntg(G, xc, yc, R, n) postup gring(z): postup gpolar(t): plovák X, y X ← xc + z * cos(t) y ← yc + z * hřích(t) vrátit se G(X, y) celé číslo m ← kolo(n*z/R) vrátit se z * Intg(gpolar, 0, 2 * π, m) vrátit se Intg(gring, 0, R, n)
Tento kód používá postup integrace Intg ve dvou úrovních. Vnější úroveň (poslední řádek) používá Intg vypočítat integrál z gring(z) pro z pohybující se od 0 do R. Definuje vnitřní úroveň (od předposledního řádku) gring(z) jako linka integrální z G(X,y) přes kruh se středem (xc,yc) a poloměr z.
Dějiny
Procedurální parametry byly vynalezeny před dobou elektronických počítačů autorem matematik Alonzo Church, jako součást jeho lambda kalkul model výpočtu.
Procedurální parametry jako funkci programovacího jazyka představil ALGOL 60. Ve skutečnosti měl ALGOL 60 silnývolat podle jména "mechanismus předávání parametrů, který by mohl zjednodušit některá použití procedurálních parametrů; viz Jensenovo zařízení.
Procedurální parametry byly podstatným rysem Programovací jazyk LISP, který rovněž zavedl koncept uzavření funkce resp funarg. The Programovací jazyk C. umožňuje ukazatele funkcí být předány jako parametry, které dosahují stejného cíle, a jsou často používány jako zpětná volání v programování řízené událostmi a jako obslužné rutiny chyb. Pouze několik moderních překladačů jazyka C však umožňuje definice vnořených funkcí, takže jeho další použití jsou relativně neobvyklá. Procedurální parametry byly poskytovány také v Pascalu spolu s definicemi vnořených procedur; protože však standardní Pascal neumožňoval samostatnou kompilaci, byla tato funkce také v tomto jazyce málo používána.
Viz také
tento článek ne uvést žádný Zdroje.Prosince 2009) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |