Obsah
1. Funkce pro porovnání skalárních hodnot i prvků polí
3. Malý dáreček Lispařům – funkce „take“ a „drop“
4. Použití funkcí „take“ a „drop“
7. Hierarchické datové struktury
1. Funkce pro porovnání skalárních hodnot i prvků polí
Podobně jako v prakticky všech ostatních programovacích jazycích, je i v jazyku APL k dispozici mechanismus umožňující vzájemné porovnání číselných hodnot či znaků. Zatímco v mnoha jazycích je tento mechanismus realizován pomocí relačních operátorů, v APL se jedná o primitivní dyadické funkce reprezentované pomocí symbolů, které známe z matematiky. Ostatní programovací jazyky sice některé z těchto symbolů taktéž využívají, ale omezují se pouze na ty znaky, které lze nalézt v tabulce ASCII, což mj. znamená, že například symbol ≤ bývá nahrazen dvojicí znaků <= atd. Největší problémy bývají se symbolem =, jenž může mít význam relační operace „rovná se“ nebo přiřazení (což vůbec neodpovídá původnímu matematickému významu tohoto symbolu). V jazyku APL je přiřazení realizováno matematickým symbolem ←, takže zde k nedorozumění nedochází. V následující tabulce jsou vypsány všechny dyadické primitivní funkce určené pro porovnání číselných hodnot či znaků:
Symbol | Unicode | Význam funkce |
---|---|---|
< | 003C | menší než |
≤ | 2264 | menší nebo rovno |
= | 003D | rovno |
≥ | 2265 | větší nebo rovno |
> | 003E | větší než |
≠ | 2260 | nerovno |
∈ | 220A | obsahuje (dotaz na existenci prvku v poli) |
Všechny výše uvedené funkce vrací v případě porovnání dvou skalárů (tj. dvojice čísel či dvojice znaků) hodnotu 1 pokud daná podmínka skutečně platí a hodnotu 0 v opačném případě. Tyto hodnoty lze považovat za hodnoty pravdivostní (například v Javě představované typem boolean a v C++ typem bool), protože na ně lze aplikovat Booleovské operace logického součtu (∨), součinu (∧), ekvivalence (=), nonekvivalence (≠) atd. Čtenáři předchozích částí tohoto článku se jistě ptají, co se stane, pokud se porovnává dvojice polí, tj. například vektorů či matic. Jazyk APL samozřejmě takové porovnání podporuje (díky tomu opět může dojít k ušetření programových smyček) a vrací pole o stejném počtu dimenzí i velikosti, jako pole porovnávaná, přičemž prvky tohoto výsledného pole mají nastaveny hodnoty 0 nebo 1 podle toho, zda zapsaná podmínka neplatí či naopak platí (pole se porovnávají prvek po prvku). Význam takto vrácené hodnoty si vysvětlíme v následujícím textu, nejprve se však podíváme na několik jednoduchých příkladů:
10 < 20 1 10 ≥ 20 MATICE1 ← 2 2 ρ 1 2 3 4 MATICE2 ← 2 2 ρ 4 3 2 1 MATICE1 1 2 3 4 MATICE2 4 3 2 1 MATICE1 < MATICE2 1 1 0 0 Prodeje ← 1100 1200 1300 900 850 930 1050 970 Prodeje > 1000 1 1 1 0 0 0 1 0
Zastavme se u posledního příkazu, v němž se provedlo porovnání vektoru (přesněji všech prvků vektoru) se skalární hodnotou. To je povolená operace, podobně jako například přičtení skalární hodnoty ke všem prvkům vektoru (viz první část článku o jazyku APL), ale její výsledek (v tomto případě vektor binárních hodnot) lze využít k mnoha účelům, například ke zjištění, v kolika měsících přesáhly prodeje hodnotu 1000; samozřejmě opět bez použití programové smyčky, která je nahrazena operátorem reduce (/) spolu s funkcí součtu (+). Nejbližším ekvivalentem následujícího příkazu je pravděpodobně SQL dotaz SELECT count(*) FROM prodeje WHERE value > 1000:
Prodeje ← 1100 1200 1300 900 850 930 1050 970 +/Prodeje > 1000 4
Typové kolečko v minulosti používané v tiskárnách při tisku programů v jazyce APL. Tento typ tiskáren obsahoval rotující kolečko nebo „soudek“ se všemi tisknutelnými znaky. Kolečko se při své rotaci posouvalo nad papírem (podobně jako tisková hlava jehličkových tiskáren) a ve chvíli, kdy se natočilo do správné polohy, bylo přitisknuto přes barvicí pásku k papíru. Výsledkem byl na svou dobu velmi kvalitní tisk, který odpovídal kvalitě psacích strojů. Nevýhodou typového kolečka bylo to, že se muselo při požadavku na změnu znakové sady (národní znaky, symboly APL, kurzíva) ručně vyměnit.
2. Komprese polí
S vektory či maticemi obsahujícími binární hodnoty úzce souvisí i funkce provádějící takzvanou kompresi polí. Jedná se o dyadickou primitivní funkci představovanou symbolem /, která na základě pole (vektoru, matice) obsahujícího pouze binární hodnoty 0 nebo 1 vybere z jiného pole o stejné dimenzi i velikosti ty prvky, u nichž je odpovídající binární hodnota rovna jedničce. Nejlépe si funkci komprese pole ukážeme na jednoduchém příkladu, ve kterém bude opět použit vektor Prodeje, s nímž jsme se již setkali v předchozí kapitole:
Prodeje ← 1100 1200 1300 900 850 930 1050 970 Prodeje 1100 1200 1300 900 850 930 1050 970 0 1 0 1 0 1 0 1 / Prodeje 1200 900 930 970
Binární vektor lze samozřejmě získat na základě jiného příkazu; například je možné vzít výsledek funkce porovnání (relace) popsané v předchozím odstavci a na základě hodnoty výsledného binárního vektoru vybrat z pole Prodeje jen hodnoty odpovídající zvolené podmínce:
Prodeje ← 1100 1200 1300 900 850 930 1050 970 (Prodeje > 1000) / Prodeje 1100 1200 1300 1050
V případě, že je zapotřebí získat indexy prvků a nikoli jejich hodnoty, můžeme si vypomoci vektorem zkonstruovaným pomocí funkce ι (jóta) se stejnou délkou, jako má původní vektor:
Prodeje ← 1100 1200 1300 900 850 930 1050 970 Prodeje 1100 1200 1300 900 850 930 1050 970 Prodeje > 1000 1 1 1 0 0 0 1 0 ρProdeje 8 ιρProdeje 1 2 3 4 5 6 7 8
Máme tedy dva mezivýsledky, oba ve formě vektoru o shodné délce (konkrétně vektor 1 1 1 0 0 0 1 0 a 1 2 3 4 5 6 7 8), které je možné zkonstruovat a současně i vzájemně zkombinovat v jednom příkazu a získat tak indexy prvků odpovídajících zapsané podmínce:
(Prodeje>1000)/ιρProdeje 1 2 3 7
3. Malý dáreček Lispařům – funkce „take“ a „drop“
Programovací jazyk APL obsahuje i dvojici funkcí, které se používají pro manipulaci se seznamy, jenž jsou reprezentovány pomocí vektorů, tj. jednodimenzionálních polí. Jedná se o funkce pojmenované „take“ a „drop“. Funkce „take“, která se zapisuje pomocí symbolu ↑, slouží k získání prvních n prvků seznamu. Pokud je použita monadická forma této funkce, vrátí se pouze první prvek (což v Lispu odpovídá funkci car), v případě použití dyadické formy se vrátí takový počet prvků, jaký udává hodnota prvního parametru této funkce (druhým parametrem je samotný seznam). Naproti tomu funkce „drop“ zapisovaná pomocí symbolu ↓ „zahodí“ prvních n prvků seznamu a následně vrátí jeho zbytek (takže 1↓ odpovídá v Lispu funkci cdr). U obou funkcí lze n zadat i jako záporné číslo. V tomto případě se prvky vybírají či zahazují z konce seznamu a nikoli z jeho začátku. Následuje jednoduchý příklad ukazující vlastnosti obou výše zmíněných funkcí „take“ a „drop“. V příkladu jsou použita záporná čísla, která jsou označena symbolem ¯ (overbar, high-minus) a nikoli funkcí – (minus):
Seznam ← ι10 Seznam 1 2 3 4 5 6 7 8 9 10 1 ↑ Seznam 1 1 ↓ Seznam 2 3 4 5 6 7 8 9 10 ↑ Seznam 1 4 ↑ Seznam 1 2 3 4 5 ↓ Seznam 6 7 8 9 10 ¯1 ↑ Seznam 10 ¯1 ↓ Seznam 1 2 3 4 5 6 7 8 9
4. Použití funkcí „take“ a „drop“
Funkce „take“ a „drop“ je možné použít i ke složitějším výpočtům s vektory, opět (jak je tomu v programovacím jazyce APL zvykem) bez použití programových smyček. Jedná se o výpočty, ve kterých je nutné provádět aritmetické či logické operace se sousedními hodnotami uloženými ve vektoru, a to tehdy, když není možné použít minule popsané operátory reduce a scan. Například budeme chtít vypočítat meziměsíční rozdíly mezi tržbami nějaké firmy (tržby jsou uloženy ve vektoru Trzby), a to jak v absolutních hodnotách, tak i rozdíly vyjádřené v procentech poklesu či naopak vzrůstu. Nejprve si vytvoříme dva pomocné vektory, z nichž jeden neobsahuje první prvek původního vektoru a druhý naopak neobsahuje jeho prvek poslední. Vytvoření pomocných vektorů zajistí funkce „drop“ (bylo by sice možné použít i funkci „take“, ale u té by se musela vypočítat délka vektoru, což je zbytečně komplikované):
Trzby ← 56 59 67 64 60 61 68 73 78 75 81 84 Trzby 56 59 67 64 60 61 68 73 78 75 81 84 1 ↓ Trzby 59 67 64 60 61 68 73 78 75 81 84 ¯1 ↓ Trzby 56 59 67 64 60 61 68 73 78 75 81
Výpočet rozdílů mezi jednotlivými měsíčními tržbami je po získání pomocných vektorů triviální, neboť tyto vektory stačí od sebe odečíst:
(1 ↓ Trzby) - (¯1 ↓ Trzby) 3 8 ¯3 ¯4 1 7 5 5 ¯3 6 3
Následuje vzorec pro výpočet růstu či poklesu tržeb vyjádřeného v procentech, opět bez použití programových smyček a pomocných proměnných:
100 × ((1 ↓ Trzby) ÷ (¯1 ↓ Trzby)) - 1 5.35 13.56 ¯4.48 ...
V případě nejistoty, zda se nejdříve provede odečtení jedničky od mezivýsledku či vynásobení mezivýsledku hodnotou 100 si připomeňme, že v jazyku APL se parametry všech funkcí vyhodnocují zprava doleva, tj. nejdříve je od podílu odečtena jednička a teprve poté je proveden převod na procentní vyjádření výsledku celého výpočtu (pomocí závorek se samozřejmě dá pořadí vyhodnocování v případě potřeby upravit).
5. Operátor „outer product“
V předchozí části tohoto článku jsme se zabývali významem operátorů v programovacím jazyce APL a taktéž jsme si některé operátory popsali. Jednalo se o operátory „reduce“, „scan“ a „axis“. Ovšem v APL je možné použít minimálně další tři operátory, přičemž modernější verze interpretrů a překladačů tohoto jazyka navíc zavádí i několik operátorů dalších. V následující tabulce jsou pro připomenutí vypsány základní operátory, které by měly být dostupné ve všech implementacích programovacího jazyka APL:
Operátor | Unicode | Jméno |
---|---|---|
¨ | 00a8 | each |
/ | 002f | slash, reduce |
\ | 005c | backslash, scan |
[] | 005b, 005d | axis |
. | 002e | inner product |
◦. | 25e6, 002e | outer product |
Jedním z prozatím nepopsaných operátorů je operátor nazvaný „outer product“ zapisovaný dvojicí symbolů ◦. (kolečko+tečka) za níž následuje jméno či symbol nějaké dyadické funkce. Tento operátor je založen na principu aplikace zvolené dyadické funkce na dvojici vektorů x a y, přičemž vybraná funkce je aplikována na všechny možné kombinace složek prvního a druhého vektoru. Výsledkem je matice Z obsahující v prvku zij návratovou hodnotu funkce aplikované na prvky xi a yj. Nejlépe si význam i princip práce tohoto operátoru vysvětlíme na příkladu, ve kterém se pokusíme vypsat část tabulky malé násobilky:
1 2 3 4 5 ◦.× 1 2 3 4 5 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
Programátoři v APL by ale spíše napsali:
(ι5)◦.×(ι5) 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
V první části článku o jazyce APL jsme si uvedli i primitivní funkci *, která slouží k umocnění dvou čísel, tj. provedení operace xy. Tabulku mocnin prvních čtyř přirozených čísel lze získat snadno:
(ι4)◦.*(ι4) 1 1 1 1 2 4 8 16 3 9 27 81 4 16 64 256
Tento operátor je samozřejmě možné použít i v kombinaci s dalšími funkcemi, nejenom s násobením a umocňováním. Poměrně často se používá například ke konstrukci jednotkové matice či trojúhelníkové matice obsahující pouze prvky s hodnotou 0 a 1. Konstrukce těchto matic je s využitím výše uvedených porovnávacích (relačních) funkcí velmi snadná a rychlá:
(ι5)◦.=(ι5) 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 (ι5)◦.<(ι5) 0 1 1 1 1 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 0 0 0 0 0 (ι5)◦.≤(ι5) 1 1 1 1 1 0 1 1 1 1 0 0 1 1 1 0 0 0 1 1 0 0 0 0 1 (ι5)◦.≥(ι5) 1 0 0 0 0 1 1 0 0 0 1 1 1 0 0 1 1 1 1 0 1 1 1 1 1
6. Operátor „inner product“
Druhý z doposud nepopsaných operátorů je operátor „inner product“ zapisovaný formou tečky okolo které se uvádí programátorem zvolená dvojice funkcí (může se jednat jak o uživatelské funkce, tak i o funkce primitivní). V podstatě se jedná o zobecněnou operaci násobení matic, ovšem s tím rozšířením, že obě aritmetické operace použité při násobení matic (tj. součin a součet) je při použití operátoru „inner product“ možné zadat formou dvojice dyadických funkcí. To znamená, že pouze při použití cca dvaceti základních primitivních funkcí je možné vytvořit až 400 jejich kombinací a nahradit tak poměrně značnou část (nejenom maticových) algoritmů pouhou aplikací jednoho operátoru na dvojici funkcí. Kromě násobení matic lze například pomocí „inner productu“ vyjádřit hodnotu polynomu pro libovolné x (polynom je zadán vektorem koeficientů ai) atd.
7. Hierarchické datové struktury
Ve všech předchozích příkladech jsme používali buď skalární hodnoty, vektory (jednorozměrná pole) nebo pravidelné matice (dvourozměrná pole). Programovací jazyk APL však ve svých moderních implementacích podporuje i hierarchické datové struktury, které jsou ovšem stále reprezentovány pomocí polí. Jednou z nejpoužívanějších struktur jsou vnořené seznamy, na které se lze také dívat jako na „zubaté“ pole, resp. jako na matici s nestejně dlouhými řádky. Zápis takové struktury je velmi jednoduchý (povšimněte si, že při inicializaci není nutné uvádět dimenze ani velikost pole):
DATA ← (1 2 3) (4 5) (6 7) (8 9 10 11)
Předchozí struktura představuje vektor, jehož prvky jsou taktéž vektory. Podobnou strukturu lze vytvořit i z matic – prvkem matice totiž může být skalární hodnota, vektor, matice či pole o prakticky libovolné dimenzi (většinou jsme omezeni 63 dimenzemi, takže se o skutečné omezení ani nejedná). Následující příkaz vytvoří tabulku (matici) o dvou řádcích a třech sloupcích. První prvek matice je taktéž maticí, tentokrát o velikosti 2×2 prvky, druhý prvek je seznamem (vektorem) o pěti prvcích, třetí prvek je řetězcem (seznamem šesti znaků) atd. Povšimněte si nutnosti uzávorkování některých podvýrazů:
NEST ← 2 3ρ(2 2ρι4) (ι5) 'HELLO!' (2 4ρι8) 23 (3 2ρ 'APL') NEST 1 2 1 2 3 4 5 HELLO! 3 4 1 2 3 4 23 APL APL 5 6 7 8 APL APL APL APL
Rozměr pole lze zjistit, jak už víme z předchozích částí seriálu, pomocí monadické formy primitivní funkce ρ:
ρNEST 2 3
Při práci s hierarchickými strukturami je někdy nutné zjistit stupeň zanoření zpracovávané datové struktury. Pro zjištění stupně zanoření jakéhokoli objektu zpracovávaného jazykem APL je určena funkce depth zapisovaná pomocí symbolu ≡. Platí, že skalární hodnoty mají vždy stupeň zanoření roven nule, kdežto pole (vektory, matice, …) obsahující pouze skalární hodnoty mají stupeň zanoření 1. Výše uvedené pole NEST má stupeň zanoření roven dvěma, protože jako svůj prvek obsahuje matice. Vlastnosti funkce ≡ si můžeme snadno ověřit na několika hodnotách:
≡42 ≡1 2 3 1 ≡2 2ρ3 4 5 6 1 ≡NEST 2
Programovací jazyk APL oplývá mnoha dalšími vlastnostmi, které jsme si nestačili v tomto článku popsat. Některé z těchto vlastností budou vysvětleny v následující části seriálu, v níž se budeme věnovat programovacímu jazyku J, který z APL ideově vychází (není se ostatně čemu divit, protože oba jazyky mají společného autora).
8. Literatura
- Ajay Askoolum, „System Building with APL + WIN,“
Wiley, ISBN: 0–470–03020–8, August 2006. - Brown et. al. „APL2 at a Glance,“
Prentice Hall, ISBN 0–13–038670–7. - T. Budd, „An APL Compiler,“
Springer-Verlag. - Maurice Dalois, „Introduction to APL*PLUS PC,“
- J. Ever and C. Fair, „Guidelines for APL Systems,“
DPD 22 IBM 037301, March 1976. - Gilman and Rose, „APL – An Interactive Approach,“
Wiley, ISBN 220–471–30022–5. - Ulf Grenander, „Mathematical Experiments on the Computer,“
Academic Press, 1982, ISBN 0–12–301750–5. - Kent Haralson, „Useful APL Defined Functions“,
IBM Technical Report, TR 00.2409, Feb. 8 1973. - Timothy Holls, „APL Programming Guide,“
IBM G320–6103, 1978, and G320–6735, 1981. - IBM, „APL2 Programming: Language Reference“
(Version 2, SH21–1061; Version 1, SH20–9227). - IBM, „The APL Handbook of Techniques“,
IBM publication number S320–5996, April 1978. - IBM, „The IBM System Journal, V. 30, No. 4 (1991)“,
Special Issue Devoted to APL. - MicroAPL, „Learning APL with APLX“,
Version 5.0 July 2009 - A.D. Falkoff, K.E Iverson, E.H Sussenguth, „A formal description of System/360,“
The IBM System Journal, V. 3, No. 3 (1964) - K. E. Iverson, „A Programming Language“,
Wiley, 1962. - K. E. Iverson, „Algebra : an algorithmic treatment“,
APL Press 1977, Copyright 1972 by Addison Wesley,
Preliminary Edition entitled „Elementary Algebra“
Copyright 1971 by IBM Corporation.
- K. E. Iverson, „Elementary analysis“,
APL press 1976, Preliminary Edition „Elementary Functions“
Copyright 1974 by IBM Corporation ISBN 0–917326–01–6
- K. E. Iverson, „An introduction to APL for Scientists and Engineers“,
APL Press 1976,
First published by IMB Corporation as Technical Report No 320–3019 March 1973 – ISBN 0–917326–04–0
- K. E. Iverson, „APL in exposition“,
APL Press 1976,
First published by IBM Corporation as Technical Report No 320–3010 March 1973 – ISBN 0–917326–02–4.
- K. E. Iverson, „Introduction To APL“,
(1984-APL Press Palo Alto) ISBN 0–917326–14–8. - K. E. Iverson, „A personal view of APL,“
IBM Systems Journal, - K. E. Iverson, „Concrete Mathematics Companion“.
- S. Kamin, „Programming Languages: An Interpreter-Based Approach,“
contains (among other things) toy implementations of Lisp, APL, Scheme, SASL, CLU, Smalltalk, and Prolog, Addison-Wesley, 1990, ISBN 0–201–06824–9. - Bernard LEGRAND, „Les APL Etendus,“
Masson, Paris, 1994. An introduction to modern APL (French). - Jon McGrew, „An Introduction to APL2,“
IBM (SH20–9229). - James A. Mason, „Learning APL: An Array Processing Language,“
Harper & Row Publishers Inc., New York, 1986, ISBN 0–06–044243–3 260 pp. - Peelle, „APL an Introduction“,
Holt, Rinehart & Winston, ISBN 0–03–004953–9. - Reiter & Jones, „APL with a Mathematical Accent“,
Brooks/Cole ISBN 0–534–12864–5, (now being distributed by Chapman & Hall). - C. Reiter, „Fractuals Visualization and J“,
Iverson Software, Inc, 1995 ISBN 1–895721–11–3. - Adrian Smith, „APL, A Design Handbook for Commercial Systems,“
Wiley series in information processing, Wiley & Sons, 1982, ISBN 0–471–10092–7. - D. Stiers, M.J. Goovaerts, J. De Kerf, „APL – The Language and its Actuarial Applications“
- Norman D. Thomson, Raymond P. Polivka, „APL2 in Depth,“
Springer-Verlag, 1995, ISBN 0–387–94213–0. - Jerry R. Turner, „APL IS EASY!,“
Manugistics, 1993. - „SHARP APL Reference Manual,“
2nd ed., Soliton Associates Limited PC Version: Iverson Software, 1993, ISBN 1–895721–07–5. - „A Source Book in APL,“
APL Press, 1981, ISBN 0–917326–10–5. - „J Phrases,“
Iverson Software, 1996, ISBN 1–895721–12–1 - „Exploring Math“, Iverson Software, 1996, ISBN 1–895721–13-X
- „J Primer,“
Iverson Software, 1996, ISBN 1–895721–14–8 - Linda Alvord and Norman Thomson, „Easy-J: An Introduction to the World's most Remarkable Programming Language“
October 2002
9. Odkazy na Internetu
- APL – A Glimpse of Heaven
http://www.vector.org.uk/…/legrand.htm - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?… - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/…apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/…ects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/…contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/…l/whyapl.htm