Sfairadora

  • Referenční příručka

Cyklus for

for(Typ příznak řídící-proměnná = DOMÉNA FILTR INICIÁLNÍ-HODNOTA)
blok
for(Typ příznak řídící-proměnná = DOMÉNA FILTR INICIÁLNÍ-HODNOTA)
blok
until(podmínka)
blok2
for(Typ příznak řídící-proměnná = DOMÉNA FILTR INICIÁLNÍ-HODNOTA)
blok
until(podmínka)
blok2
else
blok3
DOMÉNA je některá z možností:
N0..Nlimit
N0, N1..Nlimit
N0..Nlimit by krok
sekvence
FILTR je buď prázdný nebo má formu:
& podmínka-filtru
INICIÁLNÍ-HODNOTA je buď prázdná nebo má formu:
, výraz-iniciální-hodnoty
Cyklus for vytvoří řídící proměnnou s názvem zadaným identifikátorem řídící-proměnná. Do této proměnné jsou postupně přiřazovány hodnoty z určené domény. Pro každou hodnotu je vyhodnocen blok (tělo cyklu). Tělo cyklu je tedy vyhodnoceno tolikrát, kolik prvků je obsaženo v doméně.
Hodnotou cyklus for je hodnota posledního vyhodnocení bloku. Pokud blok nebyl vyhodnocen ani jednou, je výsledkem iniciální hodnota jeho typu – tj. pokud je například výsledkem vyhodnocení bloku celé číslo a jeho doména je prázdná, výsledkem bude 0. Pokud je zadána iniciální hodnota, je výsledná hodnota bloku a tedy i celého cyklu for vždy stejného typu, jakého je iniciální hodnota – viz níže sekci Agregace. Pokud je zadána větev until, je výsledek určen jejím blokem2 (resp. blokem3 větve else) – viz níže sekci Vyhledávání.

Doména

Doménou je buď posloupnost čísel (celých či reálných) nebo sekvence. Kromě čísel lze zadávat též domény znaků (typ Char). Posloupnost čísel je zadána jako interval daný první a poslední hodnotou (N0..Nlimit). V tom případě se procházejí čísla počínaje hodnotou N0 po jedné až k hodnotě Nlimit včetně této hodnoty. Pokud je hodnota Nlimit menší než hodnota N0, cyklus se neprojde ani jednou. Pokud je zadána ještě hodnota N1, je z rozdílu N1–N0 určen krok, kterým se mají hodnoty procházet. Pokud by byla hodnota N1 větší než Nlimit, hodnoty N1 ani Nlimit, nebudou procházeny. Krok může být rovněž zadán přímo klauzulí by.
Příklady domén:
5..10 5, 6, 7, 8, 9, 10
10..5 by -1 10, 9, 8, 7, 6, 5
0, 2..10 0, 2, 4, 6, 8, 10
0, 2..9 0, 2, 4, 6, 8
0, –1..10 prázdná doména, cyklus se neprovede ani jednou
1, 1.1..2 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0,
10..0 by –2 10, 8, 6, 4, 2, 0
'a'..'e' by 2 'a', 'c', 'e'
Doména zadaná jako sekvence může být buď odkaz na sekvenci (tabulku) v datech dokumentu, konstanta typu sekvence (např. {"leden", "únor", "březen"}), popřípadě samozřejmě libovolný výraz, jehož výsledkem je sekvence.
Doménou může být i OLE objekt, pokud je kolekcí.

Řídící proměnná

Výraz Typ udává typ řídící proměnné. Pokud lze typ řídící proměnné odvodit ze zadání domény, není třeba jej uvádět. To je obzvlášť výhodné, pokud se prochází přes řádky tabulky, protože typ řádků tabulky může být poměrně složitá struktura.
Před názvem řídící proměnné může být zadán příznak &, který udává, že řídící proměnná prochází doménu odkazem, tedy že postupně obsahuje reference na procházené prvky místo jejich hodnot. Odkazem lze procházet pouze sekvenci, která je sama zadána referencí na datový objekt (l-hodnotou). Výhoda procházení sekvence odkazem je dvojí. Jednak lze během procházení měnit hodnotu prvků sekvence (řádků tabulky), jednak je pro složitější tabulky tento způsob procházení efektivnější, protože při procházení hodnotou se vždy hodnota celého řádku okopíruje do řídící proměnné.
Příklad:
for(&prvek = document.data.zaměstnanci)
(
if(prvek.výkon>10)
prvek.mzda *= 1.15
)
Zde je zaměstnancům s hodnotou sloupce výkon vyšším než 10 zvýšena mzda od 15 %.

Užití filtru

Doménu, přes kterou se iteruje, lze dále upravit pomocí filtru. Filtr se zapisuje za vlastní určení domény oddělený znakem &. Filtr je podmínka (výraz vracející hodnotu typu Bool), která určuje, zda se pro daný prvek má tělo vykonat. Pro každý prvek domény se nejprve vyhodnotí podmínka filtru a pokud je výsledek FALSE, tělo se nevyhodnocuje, ale přejde se na další prvek domény.
Užití filtru oproti podmínce uvnitř bloku má výhodu jednak při agregaci (popsané níže), jednak se správně určuje, zda jde o poslední průchod cyklem při použití operátoru is_last_pass.
Příklad:
for(&prvek = document.data.zaměstnanci & prvek.výkon>10)
(
prvek.mzda *= 1.15
)
Tento příklad je ekvivalentní výše uvedenému.

Agregace

Jedním z typických užití cyklu je agregace hodnoty z dané domény. Tedy například výpočet součtu, minima, výběru prvků určité vlastnosti a podobně. Jazyk Enki umožňuje jednoduše provádět výpočty agregované hodnoty pomocí cyklu for. K tomu se zavádí symbol @řídící-proměnná, který obsahuje hodnotu těla při předchozím průchodem cyklem (prvky přeskočené pomocí filtru se nepočítají). Vzhledem k tomu, že užitím tohoto symbolu uvnitř těla cyklu vede efektivně k připojení další hodnoty k hodnotě stávající, lze tento symbol nahlížet také jako akumulátor hodnoty.
Při prvním průchodu má akumulátor nastavenu výchozí hodnotu typu těla cyklu. Vzhledem k tomu, že v některých případech může být obtížné automaticky určit typ vracený tělem cyklu a rovněž proto, že iniciální hodnota daného typu nemusí být vždy požadovanou výchozí hodnotou akumulátoru, je možné za zápisem domény cyklu určit výchozí hodnotu akumulátoru. Výchozí hodnota se odděluje čárkou. Je-li třeba explicitně zadat typ výchozí hodnoty (a tím i typ akumulátoru), lze použít operátor přetypování.
Příklad 1:
var Int sum = for(i = 1..10) (@i+i)
Vypočte součet čísel od jedné do deseti.
Příklad 2:
var Real mp = for(&prvek = document.data.zaměstnanci)
(max(@prvek, prvek.plat))
Určí maximální plat zaměstnance.
Příklad 3:
var Int faktoriál = for(i = 1..10, 1) (@i*i)
Výpočet 10! (faktoriál). Hodnota akumulátoru musí být kvůli násobení nastavena na 1.
Příklad 4:
var String[*] seznam = for(&prvek = document.data.zaměstnanci &
prvek.plat > 20000,
[String[*]]{})
(@prvek # prvek.jméno)
Vytvoří seznam jmen zaměstnanců s platem nad 20000. Klauzule [String[*]]{} určuje výchozí hodnotu akumulátoru jako prázdnou sekvenci řetězců. Nové prvky se přidávají do seznamu operátorem spojení sekvencí #.

Vyhledávání

Dalším typickým užitím cyklu je vyhledávání. Pro usnadnění vyhledávání je určena větev until (a případně else). Pokud je uvedena větev until, po každém vyhodnocení těla cyklu je ještě vyhodnocena podmínka větve until. Pokud je splněna (výraz vrací TRUE), provádění cyklu se ukončí, vyhodnotí se blok2 větve until a jeho hodnota se vrátí jako výsledek cyklu for. Podmínka ve větvi until tedy zadává podmínku toho, co se hledá, a blok2 hodnotu, která se vrátí jako nalezená hodnota. Pokud je zadána větev until, ale její podmínka nebyla splněna pro žádný prvek domény, vyhodnotí se po posledním průchodu cyklem blok3 větve else a jeho hodnota je výsledkem cyklu for. Větev else tedy určuje výslednou hodnotu pro případ, že hledání neuspěje. Pokud je zadána větev until, ale větev else chybí, a hledání neuspěje, je výsledkem cyklu for iniciální hodnota typu, který by vrátila větev until.
Pokud není tělo smyčky potřeba, lze jeho blok vynechat.
Vyhledáváni lze kombinovat s agregací. Symbol akumulátoru může být užit v podmínce i bloku větve unil i else.
Příklad 1:
var String jméno = for(&prvek = document.data.zaměstnanci)
until(prvek.příjmení=="Novák")
prvek.jméno
else
"";
Tento příklad nastaví do proměnné jméno jméno prvního zaměstnance v seznamu, který se jmenuje příjmením Novák. Větev else by mohla být vynechána, protože v případě neúspěchu hledání by výsledná hodnota byla iniciální hodnota typu vraceného větví until, tedy prázdný řetězec.
Příklad 2:
var Int[*] primes = for(i=2..1000 & for(j=@i)
until(i mod j==0)
FALSE
else
TRUE,
[Int[*]]{}) (@i#i);
Výpočet seznamu prvočísel menších než 1000. Prvočísla se postupně agregují v akumulátoru vnějšího cyklu – poslední řádek definuje iniciální hodnotu akumulátoru jako prázdnou sekvenci celých čísel. Tělo vnějšího cyklu přidává k akumulátoru nový nalezený prvek (operátorem zřetězení #). Jako filtr vnějšího cyklu procházejícího požadovaný interval čísel je užit další cyklus vyhledávající mezi již nalezenými prvočísly (doménou vnitřního cyklu je akumulátor vnějšího) dělitele aktuálně testovaného kandidáta na prvočíselnost. Pokud dělitele nalezne, je hodnota filtru FALSE a číslo se ve vnějším cyklu přeskočí, jinak se přidá.

Zpracování chyb

Pokud je výsledkem vyhodnocování podmínky či bloku cyklu chyba – typ Error, cyklus se ukončí a výsledkem je tato chyba. Podrobnosti jsou popsány v kapitole o zpracování chyb. Pokud se v těle cyklu nakládá s typem Error, je důležité zajistit, aby hodnota typu Error nebyla výsledkem těla cyklu. To se zajistí např. užitím konstrukce try.

Poznámky

Výrazy blok, blok2 a blok3 jsou blokem v tom smyslu, že v nich definované proměnné mají lokální platnost.
Cyklus lze předčasně ukončit příkazem break.
V cyklu for lze užít funkce pass_count udávající počet průchodů cyklem, is_firts_pass zjišťující, zda jde o první průchod a is_last_pass zjišťující, zda jde o poslední průchod.
Opakované provádění neomezené formou domény lze realizovat pomocí cyklu while.