Jazyk Scheme
Ak si myslíte, že ste videli všetko, tak teraz sa držte! Spíšem krátky súhrn jazyka Scheme pre potreby skriptovania a úpravu obrázkov (pozn.: tento popis jazyka sa vzťahuje na interpreter SIOD).
Úvod
Toto: "( )" je funkcia. I keď to nemusí byť na prvý pohľad jasné je to tak. Jazyk Scheme ako dialekt
jazyka Lisp stojí na dvoch pravidlách. Prvé je, že všetko sa uzatvára do okrúhlich zátvoriek
, druhé pravidlo znie: názov funkcie je prvý v zátvorke a zbytok sú premenné danej
funkcie.
Takže ak chceme sčítať dve čísla napíšeme (+ 5 2), kde "+" je názov funkcie.
Pozor toto: (+5 6) by
bola chyba, pretože nemáme funkciu s názvom "+5"! Takže pozor aby Vám nechýbali medzery. Takáto logika
(operátor je pred operandami) sa tiež nazýva prefixová, zo života sme zvyknutý na infixovú a takisto
exituje aj postfixová, kde operátor je až po operandoch (5 2 +), nazývaná tiež obrátená Poľská logika.
Ak by ste si chceli scheme vyskúšať interaktívne tak cez
GIMP spustite Script-fu konzolu -
Filters/Script-fu/Console. Stačí do
príkazového riadku napísať funkciu (na jeden riadok) a výsledok sa objavý na obrazovke. Je to najlepší
spôsob ako správne pochopiť jazyk.
Funkcie
Ako prvé uvediem do pozornosti funkcie, pretože program napísaný v jazyku scheme sa skladá z blokov - definícií jednotlivých funkcií. Nie je tu nejaká striktná štruktúra tak ako v Pascale. No a aby takýto program mohol aj fungovať, treba niekde definovať, ktorá funkcia sa spustí ako prvá, ako keby z vonku, ale k tomu sa dostaneme až potom. Všeobecná podoba funkcie pri volaní je:
(function_name variable_1 variable_2 ... variable_n)
Kde premenné sú oddelené len medzerou a nie čiarkou. Podobne i definovanie novej funkcie je pomocou volania inej funkcie:
(define (function_name variable_1 ... variable_n) ; body return_value )
Netreba pritom zabúdať, že celá konštrukcia (name variable ... )
vracia nejakú hodnotu (alebo pole či
list) pretože ide vlastne o volanie funkcie píslušného mena. Táto hodnota je vyššie pomenovaná ako
return_value.
Premenné
V jazyku Scheme podobne ako v Javaskripte sa typ premennej neudáva. Je to dynamicky typovaný jazyk. Každopádne, i tak môžme hovoriť o premenných uchovávajúcich reálne čísla (1.25; 0,2; ..), textové reťazce ("hallo"; "The GIMP"; apod.) a väčšie dátové štruktúry.
Podľa poľa pôsobnosti premenných ich delíme na globálne (platia v celom programe) a lokálne (ich
platnosť je len v bloku, v ktorom sú definované). Lokálne premenné sa definujú volaním funkcie
let* pričom platia len v bloku tejto funkcie. Všeobecná podoba použitia funkcie let je:
(let* ( (variable_1 value) (variable_2 value) ... ) ; block of validity of local variables )
Takto vytvorené premenné sa dajú meniť - ich hodnoty - zavolaním funkcie priradenia set!,
to je zároveň spôsob ako vytvoriť globálne premenné (definovaním pomocou set!), ale nieje
dôvod ich bežne používať:
(set! variable_name new_value)
List
Prvým typom väčšej dátovej štruktúry je list. Vopred mi prepáčte za slovíčko list, v preklade to
znamená zoznam, no nebudem používať preklad, takže si to nepomýlte s listami na strome alebo podobne.
Upozorňujem, že nejde o pole. List definujem tak isto ako inú premennú ale jej hodnota nebute text alebo
číslo, ale list: (set! variable '(a b c))
Je nutné pred zátvorkami napísať: " ' " , aby interpreter vedel, že to čo nasleduje nieje
funkcia ale list. Obsahom listu môžu byť premenné ľubovolného typu, list môže obsahovať jeden element
alebo môže byť aj prázdny. Teraz je dôležité povedať aká je skutočná štruktúra listu. List sa skladá z
hlavičky a chvosta. Hlavička je prvý prvok listu a chvost je to ostatné, preto ak máme list: '(10 a "v"),
tak v skutočnosti sa chová ako: '(10 (a ("v" ())))
- Pridanie prvku do listu:
(cons 0 '(1 2 3)) ; returns '(0 1 2 3)- Vytvorenie listu poskladaním:
-
(list "a" "b" '(1 2)) ; returns '("a" "b" (1 2)) (list 'a 'b '(1 2)) ; returns '(a b (1 2)) (list p 2 3) ; returns '(1 2 3) if p was 1 - Vyňatie hlavičky listu:
(car '(1 2)) ; returns 1- Vyňatie chvostu listu
-
(cdr '(1 2)) ; returns '(1)Pozor, funkcia
cdrvráti chvost listu, ale ako list. Treba mať na pamäti, že zatiaľ čo"'(1)"je list,"1"je hodnota. Preto na vrátenie hodnoty druhého prvku listu'(1 2)treba použiť(car (cdr '(1 2))), alebo skrátene(cadr '(1 2)). Podobne existujú funkcie:cddr,caadr,cadar, apod. (a = car, d = cdr). Na skúšku môžete vyňať trojku z listu pomocou dvoch funkcií:'( (1 2 (3 4 5) 6) 7 8 (9 10) ).
Ďalšie funkcie pre prácu s listami nájdete v tabuľke nižšie.
Pole = array
Ak budete používať polia pri skriptovaní tak si vystačíte s jednorozmernými poliami a práve tie rozoberiem. Pole je typ premennej, ktorá v sebe uchováva usporiadané a oindexované hodnoty rovnakého typu. Pole vytvoríme podobne ako iné premenné ale namiesto hodnoty sa napíše:
(set! variable_name (cons-array number_of_items 'type))
'type nieje povinné udať, ak ho napíšeme, tak za 'typ sa dá dosadiť:
'double, 'string,
'byte (čísla od -128 po 127) alebo 'lisp (čo je typ list).
Pravdaže počet prvkov poľa musí byť
celočíselný.
Vrátenie i-teho prvku poľa sa deje pomocou funkcie aref (prvý prvok má index 0, druhý
1 atd.): (aref variable_name index)
Vloženie hodnoty do i-teho prvku poľa zas funkciou aset:
(aset variable_name index new_value)
Vetvenie programu - if, cond
Všeobecná podoba if je:
(if (condition) () ; block evaluated if condition is true () ; else ) ; or (if (condition) () value)
V Pascale to je case of v jave zas switch a tu cond. Jeho schéma použitia je:
(cond ( (condition_1) (command_1) ) ( (condition_2) (command_2) ) ... ( (condition_n) (command_n) ) )
Cykli
Jediná možnosť vytvorenia cyklu je pomocou while s podmienkou na začiatku:
(while (condition) ;body of cycle ) ; repeat while condition is true
Užitočné funkcie
Všeobecná podoba funkcie pri volaní bude: (function_name param_1 paramr_2 ... )
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| < | menší | dve číselné hodnoty | TRUE/FALSE |
| > | väčší | dve číselné hodnoty | TRUE/FALSE |
| >= | väčší rovný | dve číselné hodnoty | TRUE/FALSE |
| <= | menší rovný | dve číselné hodnoty | TRUE/FALSE |
| = | rovný | dve číselné hodnoty | TRUE/FALSE |
| eq? | vráti TRUE ak x a y je ten istý objekt | x y | TRUE/FALSE |
| equal? | vráti TRUE ak x a y sú rovnaké objekty (napr porovnávanie listov alobo stringov) | x y | TRUE/FALSE |
| eqv? | vráti TRUE ak x a y je ten istý objekt alebo ak sú x a y numericky identické | x y | TRUE/FALSE |
| null? | vráti TRUE ak x je prázdny list | x | TRUE/FALSE |
| number? | vráti TRUE ak x je číslo | x | TRUE/FALSE |
| not | logicky zneguje výraz | výraz | TRUE/FALSE |
| bit-and | C & operátor | dve čísla | integer |
| bit-not | C ~ operátor | číslo | intger |
| bit-or | C | operátor | dve čísla | integer |
| bit-xor | C ^ operátor | dve čísla | integer |
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| abs | absolútna hodnota | číslo | |číslo| |
| sin | uhol je v radiánoch | uhol | double |
| asin | arcsin | číslo od -1 po 1 | uhol v rad |
| cos | uhol | double | |
| acos | arccos | číslo od -1 po 1 | uhol v rad |
| tan | uhol | double | |
| atan | arctan | číslo | uhol v rad |
| atan2 | arctan(x/y) | x y | uhol v rad |
| pow | x^y | double - x y | double |
| sqrt | druhá odmocnina | číslo | double |
| exp | e^x | x | double |
| log | prirodzený logaritmus ln() | číslo | double |
| fmod | delenie modulo | dve celé čísla | integer |
| trunc | odrezanie desatinej časti čísla | číslo | integer |
| max | max{x1;x2;...} | x1 x2 ... | číslo |
| min | min{x1;x2;...} | x1 x2 ... | číslo |
| srand | reset seedu pre rand, viz C funkcia | seed | '() |
| rand | náhodné číslo od 0 po m-1 | m | integer |
| ash | aritmetický posun hodnoty 'v' o 'b' bitov | v b | integer |
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| array->hexstr | konvertuje string alebo bytové pole do hexadecimálneho tvaru | string | string |
| number->string | konvertuje číslo podľa 'základu', ktorý môže byť číslo 8,10 alebo 16, 'šírka' a 'presnosť' sú voliteľné | x základ šírka presnosť | |
| parse-number | konvertuje string na číslo | string | číslo |
| read-from-string | prečíta string | string | výraz |
| strbreakup | vráti list s rozsekaným stringom podľa 'separátoru' | string separátor | list |
| strcmp | vráti 0 ak str1 a str2 rovnaké, -1 ak str1 je kratší ako str2, inak 1 | str1 str2 | -1/0/1 |
| strcspn | vráti polohu prvého znaku v 'str' ktorý bol nájdený v indikátore - čo je string, ak nič nenájde vráti dĺžku stringu | str indikátor | integer |
| string-append | spojenie reťazcov | textové reťazce | string |
| string-downcase | "Hallo" > "hallo" | string | string |
| string-length | počet znakov reťazca | texový reťazec | integer |
| string-lessp | vráti TRUE ak str1 je kratší ako str2 | str1 str2 | TRUE/FALSE |
| string-search | 'key' je string a funkcia vráti jeho polohu v stringu 'str', ak ho nenájde vráti () | key str | integer |
| string-trim | oreže biele znaky z okrajov reťazca (existuje aj string-trim-left a string-trim-right) | string | string |
| string-upcase | "Hallo" > "HALLO" | string | string |
| string? | vráti TRUE ak x je string | x | TRUE/FALSE |
| strspn | vráti pozíciu prvého znaku v 'str' ktorý nebol nájdený v 'indikátore' - čo je string, ak taký znak nenašiel vráti dĺžku 'str'. Príklad: (define (string-trim-left x) (substring x (strspn x " \t"))) |
str indikátor | integer |
| substring | výrez z reťazca 'str' podľa indexov 'start' a 'end' | str start end | string |
| substring-equal? | (equal? str (substring str2 start end)) | str str2 start end | TRUE/FALSE |
| unbreakupstr | opačne ako strbreakup | list separátor | string |
| length | dĺžka objektu - list, string, array | objekt | integer |
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| append | vráti list, ktorý vznikol rozšírením zo zadaných listov | listy | list |
| butlast | odstráni z listu posledný prvok, ak je tým prvkom list tak ten list | list | list |
| delq | vráti list v ktorom niesú elementy ekvivalentné 'elemntu' | element list | list |
| larg-default | vráti prvok 'listu' podľa pozície v 'indexe', ak je list krátky tak vráti 'default-hodnotu', nepočíta elemnety listu - reťazce začínajúce sa na ":" | list index default-hodnota | |
| last | vráti posledný element listu | list | element |
| make-list | vráti list danej 'dĺžky' vyplnený daným 'elementom' | dĺžka element | list |
| nreverse | zničí list, ktorý mu dáme ale vráti list s prvkami v opačnom poradí | list | list |
| nth | vráti elemnt z listu na danej pozícií, prvý element má poziciu 0 | index list | element |
| qsort | pomocou rekurzívneho utriedenia vráti list s elemntami usporiadanými pomocou predicate-fcn opierajúc sa o access-fcn, napr.:(qsort '(3 1 5) <)
|
list predicate-fcn access-fcn | list |
| quote | (qoute x) je to isté ako 'x | ||
| reverse | vráti list s prvkami v opačnom poradí | list | list |
| subset | vráti podmnožinu listu zloženú z prvkov, ktoré vyhovujú podmienke, napr.: (subset string? '("a" 5))
|
podmienka list |
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| base64encode | zkóduje string pomocou base64 | string | string |
| base64decode | dekóduje string v base64 | string | string |
| eval | vyhodnotí 'výraz' v kontexte 'prostredia' (velmi to nepoznám ale skúste napísať: (eval (read-from-string "(+ 2 1)")) |
výraz prostredie | hodnota výrazu |
| realtime | vráti čas v sekundách od 1.1. 1970 GMT | - | double |
| typeof | vráti symbol opysujúci objekt x alebo jeho kód | objekt_x | symbol |
Formy
Pod takýmto výrazom som našiel pár funkcií, ktoré majú ako svoje parametre výrazy, teda niečo ako
(function_name x1 x2 ...) alebo iné formy. Veľa o tom neviem, takže na tomto poli sa zíde ak budete
experimentovať Vy sami. K týmto formám patria aj while, if,
define (napr. "(define variable value)"
priradí hodnotu k premennej), ale tie som rozoberal už skôr.
| meno funkcie | poznámka | parametre | návratová hodnota |
|---|---|---|---|
| and | vyhodnocuje výrazy zľava doprava pokiaľ výraz vracia "not-null" hodnotu | výrazy | hodnota posledného výrazu |
| begin | vyhodnotí všetky výrazy | hodnota posledného výrazu | |
| cond | výrazy, nazvime ich položky v cond majú špeciálny tvar: (logicky-výraz výraz1 výraz2 ...) akonáhle sa príde na položku, ktorej logický výraz je pravdivý, vykonajú sa výrazy v položke (posledný výraz určí návratovú hodnotu cond) a tam sa skončí vyhodnocovanie položiek |
hodnota posledného výrazu vo vykonanej položke | |
| or | vyhodnocuje výrazy v poradí pokiaľ nenarazí na výraz, ktorý má "non-null" hodnotu, vtedy skončí | hodnota prvého výrazu s "non-null" hodnotou | |
| prog1 | vyhodnotí všetky výrazy | hodnota prvého výrazu |
Konštanty
Jazyk scheme pozná nasledovné konštanty, ich použitie je rovnaké ako ostatných premenných. Pozor, konštanty píšte tak ako sú v tabulke, jazyk scheme je casesensitive.
| meno | hodnota | poznámka |
|---|---|---|
| *pi* | 3.14159 .. | |
| TRUE | 1 | používajte TRUE a nie 1, napr.: (= log_variable TRUE) |
| FALSE | niečo iné než 1 | to isté |
Záver
Ak ste si niečím neistý, dobre padne nájsť si skript, v ktorom je to čo hľadáte a vidieť to tak ako to funguje.
Patrilo by sa tu k záveru napísať aj bibliografiu. V stručnosti to zhrniem. Zdroje som čerpal z dokumentárneho projektu pre Gimp a podobných návodov, ľahko dosiahnuteľných prostredníctvom Google ;-). Každopádne mi veľmi pomohol súhrn všetkých funkcií SIOD, ktorý je od George J. Carrette na adrese http://people.delphi.com/gjc/siod.html, z neho som dosť čerpal, takže určite nájdete niektoré podobnosti.