Obsah
1. Mainstreamové, ne-mainstreamové a esoterické programovací jazyky
2. Uiua: nevšední kombinace zásobníkového jazyka s jazykem pro práci s poli
3. Základní koncepty, na nichž je programovací jazyk Uiua postaven
4. Programovací jazyky založené na zásobníku operandů a RPN
5. Použití zásobníku v programovacím jazyku Uiua
6. Funkce pro manipulace s prvky uloženými na zásobníku
7. Základní monadické funkce pro zpracování skalárních hodnot
8. Základní dyadické funkce pro zpracování skalárních hodnot
11. Zpracování polí prvek po prvku
12. Monadické funkce pro operace nad celými poli
13. Ukázka použití vybraných monadických funkcí
14. Dyadické funkce pro operace nad celými poli
15. Ukázka použití vybraných dyadických funkcí
19. Předchozí články o rozsáhlém světu „array programmingu“
1. Mainstreamové, ne-mainstreamové a esoterické programovací jazyky
Na stránkách Roota jsme se již mohli seznámit s různými programovacími jazyky. Jednalo se jak o programovací jazyky patřící spíše do mainstreamu (do této kategorie si v současnosti dovolím zařadit Rust i Go), tak i o programovací jazyky velmi specializované (Julia či R). A zapomenout nesmíme ani na různé více či méně esoterické programovací jazyky, o nichž jsme psali v seriálu Programovací jazyky z vývojářského pekla.
Minimálně dvě skupiny programovacích jazyků, s nimiž jsme se prozatím seznámili, nepatří (alespoň nikoli v současnosti) mezi mainstream. V první skupině nalezneme jazyky založené na použití dvojice zásobníků (konkrétně na zásobníku operandů a na zásobníku návratových hodnot). Mezi tyto jazyky patří především programovací jazyk Forth, ale například taktéž jazyky Joy a Factor, které jsou Forthem jasně inspirovány. A druhou skupinou ne-mainstreamových programovacích jazyků tvoří jazyky specializované pro práci s n-rozměrnými poli, tedy zejména APL, J, BQN, K, Q či jazyk Nial.
2. Uiua: nevšední kombinace zásobníkového jazyka s jazykem pro práci s poli
V dnešním článku se ve stručnosti seznámíme s programovacím jazykem, který je možné zařadit jak mezi jazyky zásobníkové (tedy patřící do „Forthovské“ skupiny), tak i mezi jazyky určené pro práci s n-rozměrnými poli (jde tedy o „APL“ skupinu). Tento neobvyklý programovací jazyk, jehož syntaxe a sémantika je poněkud esoterická, má i dosti prapodivné jméno – Uiua (vyslovováno má být jako wee-wuh). Mohlo by se zdát, že propojení zásobníkového jazyka s jazykem pro práci s n-rozměrnými poli je poněkud umělé, ale výsledek je až překvapivě konzistentní, i když bez předchozího tréninku pochopitelně velmi špatně čitelný. Navíc je díky syntaxi zápisu umožněn a podporován tacit programming neboli point-free style, což je způsob programování bez nutnosti explicitního pojmenovávání předávaných parametrů, jemuž jsme se věnovali v článku Jazyk APL, kombinátory, vláčky a point-free style (a který je vlastně implicitně podporován prakticky všemi zásobníkovými jazyky).
3. Základní koncepty, na nichž je programovací jazyk Uiua postaven
Programovací jazyk Uiua je postaven na několika konceptech, s nimiž se podrobněji setkáme v navazujících kapitolách:
- Prvním konceptem je fakt, že operandy jsou ukládány na zásobník (stack). Zásobník zde funguje stejně, jako je tomu v mnoha klasických zásobníkových jazycích, tj. poslední prvek vložený na zásobník je umístěn na vrchol zásobníku (TOS – Top of Stack) a taktéž je jako první ze zásobníku vyjmut. Jinými slovy – jedná se o datovou struktury typu LIFO – Last In, First Out.
- Další koncept spočívá ve způsobu zpracování jednotlivých programových řádků po jejich parsingu. Operandy, funkce a modifikátory, jsou totiž čteny zprava doleva (ano, čtete správně – zprava doleva). Pokud je nalezen operand (hodnota), je uložen na zásobník, funkce své operandy čtou ze zásobníku a modifikátory mění chování funkcí. Tím je vlastně popsána celá sémantika :-)
- Operandy jsou jen dvou typů – skaláry a pole.
- Funkce mohou být monadické (s jedním operandem) nebo dyadické (se dvěma operandy). Ovšem teoreticky lze díky použití zásobníku mít i funkce s větším počtem operandů (na rozdíl od APL, kde je to minimálně problematické až nemožné).
- Funkce, které pracují se skaláry, dokážou postupně zpracovat i prvky pole či odpovídající si prvky pole (například součet polí je realizován prvek po prvku).
- Poté existují funkce pracující pouze s poli. Příkladem je funkcereshape, kterou nemá smysl aplikovat na skalární hodnotu.
- V jazyku lze nalézt i takzvané modifikátory, kam spadají například operace reduce, fold či scan apod. Jedná se o nejsilnější koncept tohoto jazyka (převzatý z APL).
- A nakonec se v jazyku nachází „podivnosti“ nazvané Planet a Ocean (viz závěrečné kapitoly).
Obrázek 1: Interaktivní webové prostředí programovacího jazyka Uiua. V současnosti si lze základní vlastnosti většiny programovacích jazyků ověřit právě v různých webových prostředích, takže není vyžadována (mnohdy zbytečně komplikovaná) instalace.
4. Programovací jazyky založené na zásobníku operandů a RPN
V úvodním textu jsme se zmínili o programovacích jazycích Forth, Joy, Factor (ale patří sem například i PostScript). I přesto, že se tyto programovací jazyky od sebe v mnoha ohledech odlišují, mají jednu důležitou vlastnost společnou – výpočty, tj. aritmetické operace, logické operace a v neposlední řadě i rozhodovací (řídicí) konstrukce jsou prováděny s hodnotami uloženými na zásobníku (ten je z tohoto důvodu nazýván zásobník operandů). Díky tomu bylo možné tyto programovací jazyky interně značně zjednodušit, protože se o transformaci výrazů z dnes běžné infixové podoby do podoby postfixové (jinak známé pod názvem převrácená polská notace/Reverse Polish Notation, Reverse Polish Notation – RPN) musí postarat sám programátor. To ve skutečnosti není nijak složité, ostatně s prakticky stejným (pseudo)problémem se musí potýkat i ti uživatelé, kteří například používají kalkulačky vyráběné společností Hewlett-Packard.
Obrázek 2: I moderní kalkulačky vyráběné společností Hewlett-Packard podporují převrácenou polskou notaci.
V této kapitole si jen v krátkosti připomeňme, že při použití zásobníku operandů přímo v programovacím jazyku jsou hodnoty na zásobník ukládány explicitně (zápis 42 tedy většinou znamená uložení této hodnoty na vrchol zásobníku operandů), aritmetické a logické operace používají implicitní adresování operandů (vždy se totiž jedná o hodnotu uloženou na vrcholu zásobníku či těsně pod ním) a kromě toho se většinou setkáme i s několika pomocnými operacemi určenými pro manipulaci s obsahem zásobníku. Tyto operace bývají nazývány dup (zduplikování hodnoty uložené na vrcholu zásobníku, zásobník se o jeden prvek zvětší), drop (odstranění hodnoty z vrcholu zásobníku operandů, zásobník se o jeden prvek zmenší), swap (prohození dvou nejvyšších prvků uložených na zásobníku, velikost zásobníku se nezmění) a rot (rotace tří nejvyšších prvků, velikost zásobníku se opět nezmění). Tyto názvy mají dnes již vlastně historický původ, protože byly použity v programovacím jazyku Forth; později se začaly používat například i v zásobníkových virtuálních strojích.
Nicméně se vraťme k zásobníku operandů a k tacit programmingu. Ve Forthu je možné napsat například následující funkci:
:foo + * ;
Tato funkce na zásobníku očekává alespoň tři číselné hodnoty, které ovšem uvnitř funkce nejsou nikde explicitně pojmenovány ani (explicitně) použity. Použití této funkce je stejně snadné jako její zápis, pochopitelně pokud si zvyknete na RPN:
3 2 1 foo . 9
Nejprve jsme na zásobník uložili tři hodnoty. Posléze se zavolala funkce foo, která tyto hodnoty nějakým způsobem zpracovala. Na nakonec byla hodnota umístěná na TOS vypsána další funkcí se jménem . (ano, tečka je ve Forthu skutečně zcela legitimní jméno funkce).
Povšimněte si, že nyní těla funkce foo:
+ *
Tělo této funkce obsahuje pouze dvě tzv. slova „+“ a „*“. Každé z těchto slov očekává na zásobníku operandů dvojici hodnot, které jsou sečteny, popř. vynásobeny a výsledek je uložen zpět na zásobník operandů. Nikde tedy není nutné psát, jak se operandy jmenují a už vůbec ne, jak se jmenuje výsledná hodnota. Navíc ani funkce foo tyto údaje neobsahuje.
5. Použití zásobníku v programovacím jazyku Uiua
Všechny dále uvedené příklady si můžeme vyzkoušet na adrese https://www.uiua.org/ přímo v interaktivním prostředí pracujícím ve webovém prohlížeči.
Obrázek 3: Nastavení, které je nutné provést v interaktivním vývojovém prostředí jazyka Uiua tak, aby se obsah zásobníku zobrazoval způsobem, který dává zkratce TOS význam.
V programovacím jazyku Uiua se nepoužívá klasická a standardní převrácená polská notace (tedy již popsaná RPN) ale určitá obdoba (přímé) polské notace, což může být poměrně matoucí. Navíc se operátory a operandy zapsané na řádku zpracovávají zprava doleva. To má sice své logické důvody, o nichž se zmíníme dále, ovšem opět se jedná o koncept, který může být dosti nezvyklý. Jak se ale tyto dvě vlastnosti, resp. jejich kombinace, projeví v praxi? Pokud například na jediný řádek zapíšeme trojici číselných hodnot, budou tyto hodnoty uloženy na zásobník (až potud je vše očekávatelné). Ovšem číselné hodnoty jsou zpracovávány zprava doleva a právě v tomto pořadí jsou uloženy na zásobník. Výsledkem tedy bude, že první zapsaná hodnota bude uložena na vrchol zásobníku operandů, tedy zcela opačně, než je tomu v klasické RPN:
1 2 3 1 2 3
Povšimněte si, že po spuštění výše uvedeného programu (ten je zapsán tučně) se v interaktivním prostředí pod programem zobrazí trojice hodnot tak, jak jsou uloženy na zásobníku. Vzhledem ke způsobu vyhodnocování zprava doleva se tedy na zásobník nejprve uloží hodnota 3, poté hodnota 2 a nakonec bude na vrchol zásobníku bude uložena hodnota 1.
Můžeme si otestovat i nepatrně odlišný program, po jehož spuštění se nejdříve na zásobník uloží hodnoty 2 a 1 (přesně v tomto pořadí) a následně se tyto hodnoty sečtou spuštěním operace +, která ze zásobníku vyjme dva prvky, sečte je a na zásobník vrátí výsledek součtu:
+ 1 2 3
Operace + ovšem ve skutečnosti pracuje pouze se dvěma nejvyššími prvky uloženými na zásobníku. Případné další prvky nejsou dotčeny:
+ 1 2 100 100 3 100 100
Operátor zapsaný zcela nalevo bude proveden nejpozději, což zde konkrétně znamená, že vynásobí hodnoty 3 a 100, přičemž výsledek opět uloží zpět na zásobník:
× + 1 2 100 100 300 100
Infixově zapsaná operace (1+2)×3 vypadá v pojetí programovacího jazyka Uiua následovně:
× + 1 2 3 9
Nebo též:
× 3 + 1 2 9
Ovšem nic nám nebrání v zápisu přes více řádků:
+ 1 2 × 3 9
nebo:
1 2 3 ×+ 9
či dokonce:
1 2 3 + × 9
6. Funkce pro manipulace s prvky uloženými na zásobníku
V programovacím jazyku Uiua existuje šest funkcí, které jsou určeny pro manipulace s prvky uloženými na zásobníku. Některé z těchto funkcí známe již z popisu zásobníkových programovacích jazyků, ovšem poslední dvě funkce jsou specifické pro Uiua. A pochopitelně, díky tomu, že se jedná o jazyk odvozený od APL, jsou všechny funkce reprezentovány jednoznakovými symboly (z Unicode):
Symbol | Jméno | Stručný popis |
---|---|---|
. | duplicate | duplikace prvku na TOS |
, | over | duplikace prvku pod TOS |
: | flip | prohození dvou nejvyšších prvků na zásobníku |
; | pop | odstranění prvku z TOS |
∩ | both | zavolá monadickou funkci na dva operandy (nebo dyadickou funkci na dvojici operandů) |
⸮ | trace | vypíše (pretty print) prvek na TOS, ovšem bez jeho odstranění ze zásobníku |
Otestování základního chování těchto funkcí:
Duplikace prvku na TOS:
. 1 2 3 1 1 2 3
Duplikace prvku pod TOS:
, 1 2 3 2 1 2 3
Prohození dvou nejvyšších prvků na zásobníku:
: 1 2 3 2 1 3
Odstranění nejvyššího prvku z TOS:
; 1 2 3 2 3
Změna znaménka u prvních dvou prvků:
∩¯ 1 2 3 ¯1 ¯2 3
Výpis podrobnějších informací o prvku s hodnotou –1:
⸮∩¯ 1 2 3 ┌╴1:1 ├╴¯1 └╴╴╴╴ ¯1 ¯2 3
7. Základní monadické funkce pro zpracování skalárních hodnot
Připomeňme si, že v programovacích jazycích odvozených od APL se rozlišuje mezi funkcemi monadickými a dyadickými. Monadické funkce mají pouze jeden operand (či parametr), kdežto dyadické funkce mají dva operandy (parametry). Nejprve si tedy popišme tu nejjednodušší skupinu funkcí. Jedná se o monadické funkce určené pro zpracování skalárních hodnot:
Symbol | Jméno | Stručný popis |
---|---|---|
¬ | not | logická negace |
± | sign | vrací –1, 0 či +1 podle znaménka operandu |
¯ | negate | změna znaménka |
⌵ | absolute value | výpočet absolutní hodnoty |
√ | sqrt | výpočet druhé odmocniny |
○ | sine | výpočet goniometrické funkce sin |
⌊ | floor | zaokrouhlení směrem dolů |
⌈ | ceiling | zaokrouhlení směrem nahoru |
⁅ | round | zaokrouhlení |
Několik příkladů (již bez popisu):
± 42 1
¯ 42 ¯42
⌵¯42 42
√⌵¯100 10
⌊1.5 1
⌈1.5⌊ 2
8. Základní dyadické funkce pro zpracování skalárních hodnot
V programovacím jazyku Uiua nalezneme i dyadické funkce, které jsou určené pro zpracování skalárních hodnot. Tyto funkce ze zásobníku získají dva prvky, provedou s nimi vybranou operaci a výsledek nebo výsledky uloží zpět na zásobník. Jedná se o následující funkce:
Symbol | Jméno | Stručný popis |
---|---|---|
= | equals | test na rovnost dvou prvků |
≠ | not equals | test na nerovnost dvou prkvů |
< | less than | test na relaci dvou prvků |
≤ | less or equal | test na relaci dvou prvků |
> | greater than | test na relaci dvou prvků |
≥ | greater or equal | test na relaci dvou prvků |
+ | add | součet |
– | subtract | rozdíl |
× | multiply | součin |
÷ | divide | podíl |
◿ | modulus | zbytek po dělení |
ⁿ | power | x^y |
ₙ | logarithm | logaritmus o zvoleném základu |
↧ | minimum | menší hodnota |
↥ | maximum | větší hodnota |
∠ | atangent | arctan pro (dvě) přepony trojúhelníku |
ℂ | complex | konstrukce komplexního čísla z reálné a imaginární složky |
U některých výše zmíněných operací je nutné si dát pozor na pořadí operandů uložených na zásobníku:
÷ 1 2 2
÷ 2 1 0.5
Logaritmus o zvoleném základu:
ₙ 10 10000 4
ₙ 10000 10 0.25
9. Pole
V programovacím jazyku Uiua se primárně rozlišují dvě skupiny typů hodnot. První skupinu tvoří atomy (atom), druhou skupinu pak pole (array). Na pole se můžeme dívat jako na skupinu atomů organizovaných podél os (axes), přičemž počet os určuje dimenzi pole. Každé pole má svůj tvar, který popisuje velikost pole měřenou podél jednotlivých os (tedy pole s tvarem [2 3 4] má rozměry 2×3×4 prvky). Os přitom může být (prakticky) libovolný počet. Další důležitou vlastností polí je, že jsou homogenní, tj. obsahují prvky stejného typu.
Pole lze ukládat na zásobník, stejně jako skalární hodnoty. A navíc platí, že monadické a dyadické funkce popsané v předchozích kapitolách, lze aplikovat i na pole – potom se takové funkce buď aplikují na všechny prvky pole (monadické funkce) nebo na všechny odpovídající si prvky ze dvou polí (dyadické funkce).
10. Konstrukce polí
V programovacím jazyku Uiua existuje literál představující celé pole. Tento literál se zapisuje formou hodnot jednotlivých prvků (musí se jednat o hodnoty), které jsou spojeny (či odděleny – záleží na úhlu pohledu) podtržítkem. Literál představující jednorozměrné pole se čtyřmi prvky se zapíše takto:
1_2_3_4 [1 2 3 4]
Můžeme také použít konstruktor pole, v němž se jednotlivé prvky zapisují do hranatých závorek a odděleny jsou nějakým bílým znakem:
[1 2 3 4] [1 2 3 4]
V tomto případě jsou ovšem prvky vyhodnocovány (nejde o literál) a to nám například umožňuje provést výpočet 1+2 a 3+4 s tím, že výsledky těchto výpočtů budou zapsány do nově zkonstruovaného pole:
[+ 1 2 + 3 4] [3 7]
Konstrukce vícerozměrného pole je snadná – prvky n-rozměrného pole jsou totiž n-1 rozměrná pole, takže použijeme konstruktor, kterému tato menší pole předáme:
[[1 2][3 4]] ╭─ ╷ 1 2 3 4 ╯
A takto vypadá konstrukce trojrozměrného pole:
[[[0 0][0 0]][[1 2][3 4]]] ╭─ ╷ 0 0 ╷ 0 0 1 2 3 4 ╯
Jazyk Uiua pracuje i s řetězci. Řetězcový skalár se zapíše následovně:
"Hello world" "Hello world"
Literál představující pole obsahující řetězce:
"Hello"_"world" ╭─ ╷ "Hello" "world" ╯
Výsledné pole ovšem musí být homogenní – všechny prvky musí být stejného typu:
"Hello"_"world"_42 Error: Cannot append character array to number array at 1:1 1 | "Hello"_"world"_4
11. Zpracování polí prvek po prvku
Jak již víme z předchozího textu, lze všechny monadické a dyadické funkce určené pro práci se skaláry použít i pro dvojici stejně velkých polí (tedy polí se shodným tvarem). Takové funkce jsou aplikovány na odpovídající si prvky polí.
Součet dvou polí prvek po prvku:
+ [1 2 3] [4 5 6] [5 7 9]
Takzvaný broadcasting umožňující přičíst hodnotu 10 ke každému prvku pole:
+ [1 2 3] 10 [11 12 13]
Výsledkem této operace je pole s pravdivostními hodnotami reprezentovanými jako 1 a 0:
≠ [1 2 3] 2 [1 0 1]
Porovnání polí prvek po prvku, výsledkem je opět pole (se shodným tvarem) obsahující výsledky porovnání:
≤ [1 2 3 4] [4 3 2 1] [0 0 1 1]
Tvary polí (shape) ovšem musí být shodné:
≤ [1 2 3 4] [4 3 2 1 0] Error: Shapes [4] and [5] do not match at 1:1 1 | ≤ [1 2 3 4] [4 3 2 1 0]
Součet dvou (dvourozměrných) matic:
+ [[1 2][3 4]] [[5 6][7 8]] ╭─ ╷ 6 8 10 12 ╯
12. Monadické funkce pro operace nad celými poli
V jazyku Uiua jsou realizovány i funkce, které pracují nad celými poli (nikoli tedy nutně prvek po prvku). Tyto funkce jsou vypsány v následující tabulce:
Symbol | Jméno | Stručný popis |
---|---|---|
⧻ | length | vrací délku pole (v první dimenzi) |
△ | shape | vrací tvar pole (což je taktéž pole) |
⇡ | range | generátor pole se sekvencí hodnot |
⊢ | first | vrací první prvek pole |
⇌ | reverse | otočí celé pole (resp. prvky v něm) |
♭ | deshape | konverze pole o libovolném počtu dimenzí na pole s jednou dimenzí (vektorem) |
¤ | fix | přidá další dimenzi (vlastně uzavře pole do dalšího pole s jediným prvkem) |
⋯ | bits | každý prvek pole se převede na pole bitů, které reprezentují jeho hodnotu |
⍉ | transpose | rotace pole |
⍏ | rise | vytvoří pole s indexy původních prvků tak, aby bylo pole seřaditelné |
⍖ | fall | dtto, ale pro opačné řazení |
⊚ | where | získání indexů těch prvků, které jsou nenulové (lze tím nahradit programovou smyčku) |
⊛ | classify | každému unikátnímu prvku pole přiřadí unikátní index (stejné prvky budou mít shodné indexy) |
⊝ | deduplicate | odstraní z pole duplikátní prvky |
□ | box | vloží pole do takzvaného boxu, který umožní tvorbu de facto heterogenních polí (jako v jazyku K) |
⊔ | unbox | opak předchozí operace – vyjme pole z boxu |
13. Ukázka použití vybraných monadických funkcí
Podívejme se nyní na způsob použití několika vybraných monadických funkcí určených pro zpracování celých polí.
Délka pole – počet prvků v nejvyšší dimenzi:
⧻ [[1 2][3 4]] 2
Získání tvaru (shape) pole:
△ [[1 2][3 4]] [2 2]
Vygenerování vektoru obsahujícího sekvenci hodnot od 0 do 9:
⇡ 10 [0 1 2 3 4 5 6 7 8 9]
Získání pole pravdivostních hodnot (reprezentovaných nulami a jedničkami) na základě porovnání prvku každého pole s konstantou 4:
≤ 4 ⇡ 10 [1 1 1 1 1 0 0 0 0 0]
Otočení pole vytvořeného funkcí range:
⇌ ⇡ 10 [9 8 7 6 5 4 3 2 1 0]
Deshape pole – převod na jednorozměrný vektor:
♭ [[1 2][3 4][5 6]] [1 2 3 4 5 6]
Kombinace funkce pro převod pole na jednorozměrný vektor s funkcí pro otočení prvků pole:
⇌♭ [[1 2][3 4][5 6]] [6 5 4 3 2 1]
14. Dyadické funkce pro operace nad celými poli
Další funkce jsou dyadické, přičemž jedním z parametrů je v tomto případě pole (a druhým parametrem může být skalár nebo taktéž pole). Jedná se o následující funkce:
Symbol | Jméno | Stručný popis |
---|---|---|
≍ | match | test, zda jsou pole totožná |
⊟ | couple | spojení dvou polí (viz příklady) |
⊂ | join | spojení dvou polí (viz příklady) |
⊏ | select | výběr většího množství prvků na základě selektorů |
⊡ | pick | výběr celých řádků na základě selektorů |
↯ | reshape | změna tvaru pole (přeskupení prvků) |
☇ | rerank | změna počtu dimenzí pole |
↙ | take | přečtení prvních n prvků z pole |
↘ | drop | pole bez prvních n prvků |
↻ | rotate | rotace prvků v poli |
▽ | keep | zachová prvky s indexy, které jsou předány v prvním parametru |
⌕ | find | vyhledání prvků z jednoho pole v jiném poli (výsledkem je pole s 0 a 1) |
∊ | member | test, zda je zadaný řádek součástí pole |
⊗ | indexof | vyhledání prvku (prvků) s vrácením indexů |
15. Ukázka použití vybraných dyadických funkcí
Opět se podívejme na využití vybraných dyadických funkcí určených pro práci s poli.
Spojení dvou polí funkcí couple:
⊟ [1 2 3 4] [5 6 7 8] ╭─ ╷ 1 2 3 4 5 6 7 8 ╯
Spojení dvou polí funkcí join:
⊂ [1 2 3 4] [5 6 7 8] [1 2 3 4 5 6 7 8]
Výběr prvků ze druhého pole pomocí indexů v poli prvním:
⊏ [1 2 3 1 2 3] [5 6 7 8] [6 7 8 6 7 8]
Změna tvaru pole (reshape):
↯ [2 3] [1 2 3 4 5 6] ╭─ ╷ 1 2 3 4 5 6 ╯
Změna tvaru pole (reshape):
↯ [3 2] [1 2 3 4 5 6] ╭─ ╷ 1 2 3 4 5 6 ╯
16. Agregační operace
Programovací jazyk Uiua však kromě poměrně rozsáhlé řady primitivních funkcí obsahuje, ostatně podobně jako již popsaný jazyk APL, několik operátorů, pomocí nichž jsou funkce aplikovány nikoli na jeden či dva parametry, ale postupně na celé vektory nebo matice (proto se nazývají agregační operace). Díky operátorům (význam tohoto slova je odlišný od významu, který toto slovo má v jiných programovacích jazycích!) je možné eliminovat velké množství programových smyček a mnohdy tak například několikařádkovou proceduru zapsat pomocí jediného výrazu:
Symbol | Jméno | Stručný popis |
---|---|---|
/ | reduce | postupná aplikace funkce na prvek a akumulátor |
∧ | fold | jako reduce, ovšem se specifikací hodnoty akumulátoru na začátku |
\ | scan | jako reduce, ovšem generuje pole se všemi mezivýsledky |
⊕ | group | výběr prvků z pole na základě zadaných indexů (tyto prvky se dostanou na stejný řádek) |
⊞ | table | v APL známý pod pojmem outer product (aplikace funkce na všechny možné kombinace prvků dvou polí) |
17. Ukázka použití základních agregačních operací
Jedním z nejdůležitějších operátorů jazyka Uiua je operátor /, který jsme si již v jednodušší podobě představili při popisu jazyka APL. Tento operátor, který se zapisuje před identifikátor primitivní či uživatelské funkce, postupně danou funkci aplikuje na první dva prvky argumentu, dále ji aplikuje na průběžný výsledek a třetí prvek atd., do doby, než jsou všechny prvky argumentu zpracovány (jinými slovy – daná dyadická funkce je jakoby zapsána mezi všechny prvky předané datové struktury, počet operací je roven n-1 v případě, že předaný vektor má počet prvků n):
Součet všech prvků pole:
/+ [1 2 3 4] 10
Součet hodnot od 1 do 9:
/+ ⇡10 45
Výpočet faktoriálu 10:
/× +1 ⇡10
Mezery nejsou nezbytné:
/×+1⇡10 3628800
Ovšem v některých případech může být lepší použití fold se specifikací prvního prvku:
∧× [1 2 3 4] 10 240
Lze zkombinovat s počátečním prvkem, který je polem:
∧× [1 2 3 4] [1 2 10] [24 48 240]
Dalším dobrým příkladem může být modifikátor nazvaný scan, který postupně prochází všemi prvky, aplikuje zvolenou funkci na aktuální prvek a akumulátor a na vstup posílá výsledek zvolené funkce. Jedná se tedy o obdobu funkce reduction z jazyka APL.
Výčet tabulky faktoriálů operátorem scan (opět zapsáno bez mezer):
\×+1⇡10 [1 2 6 24 120 720 5040 40320 362880 3628800]
A konečně si ukažme outer product. S využitím tohoto operátoru je možné zkonstruovat velké množství matic se speciálními vlastnostmi; tyto matice mohou mít samozřejmě téměř libovolnou velikost. Jedná se například o jednotkové matice (obsahují jedničky v diagonále, ostatní prvky jsou nulové), trojúhelníkové matice různého typu (jedničky se nachází pod či nad diagonálou, ostatní prvky jsou nulové) atd. Tvorba těchto matic je ilustrována na následujících příkladech, ve kterých se často používají porovnávací (relační) funkce:
⊞= ⇡10 ⇡10 ╭─ ╷ 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 ╯
⊞≤ ⇡10 ⇡10 ╭─ ╷ 1 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 1 ╯
Malá násobilka:
⊞× +1⇡10 +1⇡10 ╭─ ╷ 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 ╯
18. Závěr
Už z předchozího popisu je pravděpodobně zřejmé, že se programovací jazyk Uiua pravděpodobně nedostane do mainstreamu a dokonce je nepravděpodobné, že začne být ve větší míře používán v nice array programmingu (kde se dnes používá především Dyalog APL a poté jazyky K a Q, jenž jsou vyvíjeny společností Kx pro sice poměrně velký, ale dosti specifický sektor). Na druhou stranu je zajímavé, jak lze s využitím zásobníku a operací nad poli vytvořit programovací jazyk, v němž lze velmi snadno realizovat point-free styl (tacit programming). A jen na okraj: poslední dobou vznikly minimálně dva jazyky pro niku array programmingu. Je to právě Uiua, ale taktéž programovací jazyk BQN, který je postaven na myšlenkách APL, ovšem má některé základní koncepty promyšlenější (a možná tak představuje nejlepší cestu do světa array processingu).
19. Předchozí články o rozsáhlém světu „array programmingu“
Programovacími jazyky, které jsou z větší či menší míry odvozeny od programovacího jazyka APL, jsme se již na stránkách Roota zabývali v několika článcích (a samozřejmě i v dnešním článku). Odkazy na tyto články naleznete pod odstavcem:
- Jazyky umožňující operace s poli aneb rozsáhlý svět „array programmingu“
https://www.root.cz/clanky/jazyky-umoznujici-operace-s-poli-aneb-rozsahly-svet-bdquo-array-programmingu-ldquo/ - Specializované jazyky pro práci s N-dimenzionálními poli: jazyk J
https://www.root.cz/clanky/specializovane-jazyky-pro-praci-s-n-dimenzionalnimi-poli-jazyk-j/ - Programovací jazyky odvozené od APL: BQN a ivy aneb 1~×`1↓↕10
https://www.root.cz/clanky/programovaci-jazyky-odvozene-od-apl-bqn-a-ivy-aneb-1–1–10/ - Programovací jazyk K: důkaz, že mezi námi žijí mimozemšťané
https://www.root.cz/clanky/programovaci-jazyk-k-dukaz-ze-mezi-nami-ziji-mimozemstane/ - Programovací jazyk K: důkaz, že mezi námi žijí mimozemšťané (dokončení)
https://www.root.cz/clanky/programovaci-jazyk-k-dukaz-ze-mezi-nami-ziji-mimozemstane-dokonceni/ - Nial Array Language: další z jazyků inspirovaných APL
https://www.root.cz/clanky/nial-array-language-dalsi-z-jazyku-inspirovanych-apl/ - Programování mainframů: jazyk APL
https://www.root.cz/clanky/programovani-mainframu-jazyk-apl/ - Programovací jazyk APL: programování bez smyček
https://www.root.cz/clanky/programovaci-jazyk-apl-programovani-bez-smycek/ - Programovací jazyk APL – dokončení
https://www.root.cz/clanky/programovaci-jazyk-apl-dokonceni/ - Oslava 55 let od vzniku první implementace jazyka APL
https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/ - Jazyk APL, kombinátory, vláčky a point-free style
https://www.root.cz/clanky/jazyk-apl-kombinatory-vlacky-a-point-free-style/
20. Odkazy na Internetu
- Seriál: programovací jazyk Rust
https://www.root.cz/serialy/programovaci-jazyk-rust/ - Seriál: programovací jazyk Go
https://www.root.cz/serialy/programovaci-jazyk-go/ - Seriál: programovací jazyk Julia
https://www.root.cz/serialy/programovaci-jazyk-julia/ - Seriál: programovací jazyk R
https://www.root.cz/serialy/programovaci-jazyk-r/ - Uiua: A stack-based array programming language
https://www.uiua.org/ - uiua na GitHubu
https://github.com/uiua-lang/uiua - Nial: A powerful, interactive array language with support for flexible multiparadigm code
https://www.nial-array-language.org/ - Nial: dokumentace
https://www.nial-array-language.org/ndocs/ - Nial na GitHubu
https://github.com/niallang/Nial_Development - Nial na Rosetta Code
https://rosettacode.org/wiki/Category:Nial - Array language comparisons
https://github.com/codereport/array-language-comparisons - K language – an introduction
http://www.math.bas.bg/bantchev/place/k.html - K7 Tutorial
https://cs.nyu.edu/~shasha/papers/tutorial - An Interview with Arthur Whitney, Kx CEO and Developer of Kx Technology, January 4, 2004
https://web.archive.org/web/20150813004101/http://kx.com/arthur-interview.php - A Shallow Introduction to the K Programming Language
https://web.archive.org/web/20130801233812/http://www.kuro5hin.org/story/2002/11/14/22741/791 - A Conversation with Arthur Whitney
https://queue.acm.org/detail.cfm?id=1531242 - Anecdote about Arthur Whitney
https://news.ycombinator.com/item?id=13590065 - K – list of idioms
https://github.com/kevinlawler/kona/wiki/Idioms - Appendix A. Incunabulum
http://keiapl.org/rhui/remember.htm#incunabulum - K code study
https://docs.google.com/document/d/1W83ME5JecI2hd5hAUqQ1BVF32wtCel8zxb7WPq-D4f8/edit - K tutorial
https://github.com/kevinlawler/kona/wiki/Tutorial - K by EXAMPLE
http://vrabi.web.elte.hu/k/kbyeg.k - BQN: An APL Variant from Marshall Lochbaum (mlochbaum.github.io)
https://news.ycombinator.com/item?id=24167804 - Raytracer in 7 lines in K
http://www.nsl.com/k/ray/ray.k - Marshall Lochbaum
https://www.aplwiki.com/wiki/Marshall_Lochbaum - BQN
https://www.aplwiki.com/wiki/BQN - Co-dfns
https://www.aplwiki.com/wiki/Co-dfns - Array model
https://www.aplwiki.com/wiki/Array_model#Based_array_theory - Fonts for BQN
https://mlochbaum.github.io/BQN/fonts.html - Leading axis theory
https://www.aplwiki.com/wiki/Leading_axis_theory - A based system for general arrays
https://dl.acm.org/doi/abs/10.1145/586656.586663 - APL – A Glimpse of Heaven (2006)
https://news.ycombinator.com/item?id=19325361 - APL and J
https://crypto.stanford.edu/~blynn/c/apl.html - ivy (dokumentace)
https://pkg.go.dev/robpike.io/ivy#section-readme - ivy na GitHubu
https://github.com/robpike/ivy/ - Ivy na APL wiki
https://aplwiki.com/wiki/Ivy - Implementing a bignum calculator (slajdy)
https://talks.godoc.org/github.com/robpike/ivy/talks/ivy.slide#1 - Implementing a bignum calculator – Rob Pike – golang-syd November 2014
https://www.youtube.com/watch?v=PXoG0WX0r_E - Rob Pike na Wikipedii
https://en.wikipedia.org/wiki/Rob_Pike - Rob Pike na cat-v
http://genius.cat-v.org/rob-pike/ - NuVoc
https://code.jsoftware.com/wiki/NuVoc - J (programming language) [Wikipedia]
https://en.wikipedia.org/wiki/J_%28programming_language%29 - J – Absolutely Essential Terms
https://code.jsoftware.com/wiki/Vocabulary/AET - J – Atoms and Arrays
https://code.jsoftware.com/wiki/Vocabulary/Nouns#Atom - Why J
https://www.jsoftware.com/help/primer/why_j.htm - What is an Array?
https://vector.org.uk/what-is-an-array/ - Comments
http://www.gavilan.edu/csis/languages/comments.html - Vector (Wolfram MathWorld)
https://mathworld.wolfram.com/Vector.html - n-Tuple (Wolfram MathWorld)
https://mathworld.wolfram.com/n-Tuple.html - n-Vector (Wolfram MathWorld)
https://mathworld.wolfram.com/n-Vector.html - Matrix (Wolfram MathWorld)
https://mathworld.wolfram.com/Matrix.html - Array (Wolfram MathWorld)
https://mathworld.wolfram.com/Array.html - ND Arrays (Tensors) in different languages
https://www.youtube.com/watch?v=WbpbEilgQBc - Extending APL to Infinity\
https://www.jsoftware.com/papers/eem/infinity.htm - Vector Library (R7RS-compatible)
https://srfi.schemers.org/srfi-133/srfi-133.html - Vectors (pro Gauche)
https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html - Kawa: Compiling Scheme to Java
https://www.mit.edu/afs.new/sipb/project/kawa/doc/kawa-tour.html - Kawa in Languages shootout
http://per.bothner.com/blog/2010/Kawa-in-shootout/ - Kawa 2.0 Supports Scheme R7RS
https://developers.slashdot.org/story/14/12/13/2259225/kawa-20-supports-scheme-r7rs/ - Kawa — fast scripting on the Java platform
https://lwn.net/Articles/623349/ - Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
http://incanter.org/ - Evolution of incanter (Gource Visualization)
https://www.youtube.com/watch?v=TVfL5nPELr4 - Questions tagged [incanter] (na Stack Overflow)
https://stackoverflow.com/questions/tagged/incanter?sort=active - Data Sorcery with Clojure
https://data-sorcery.org/contents/ - Back to the Future: Lisp as a Base for a Statistical Computing System
https://rd.springer.com/chapter/10.1007/978–3–7908–2084–3_2 - Incanter Cheat Sheet
http://incanter.org/docs/incanter-cheat-sheet.pdf - Back to the Future: Lisp as a Base for a Statistical Computing System (celá verze článku)
https://www.researchgate.net/publication/227019917_Back_to_the_Future_Lisp_as_a_Base_for_a_Statistical_Computing_System - BQN: finally, an APL for your flying saucer
https://mlochbaum.github.io/BQN/ - Is BQN stable?
https://mlochbaum.github.io/BQN/commentary/stability.html - Specification: BQN system-provided values
https://mlochbaum.github.io/BQN/spec/system.html - Tutorial: BQN expressions
https://mlochbaum.github.io/BQN/tutorial/expression.html - BQN primitives
https://mlochbaum.github.io/BQN/doc/primitive.html - Function trains
https://mlochbaum.github.io/BQN/doc/train.html - BQN community links
https://mlochbaum.github.io/BQN/community/index.html - BQN UV
https://observablehq.com/@lsh/bqn-uv - APL Wiki
https://aplwiki.com/wiki/ - The Array Cast
https://www.arraycast.com/episodes/episode-03-what-is-an-array - EnthusiastiCon 2019 – An Introduction to APL
https://www.youtube.com/watch?v=UltnvW83_CQ - Dyalog
https://www.dyalog.com/ - Try APL!
https://tryapl.org/ - Lisp-Stat Information
http://homepage.cs.uiowa.edu/~luke/xls/xlsinfo/ - Sample Plots in Incanter
https://github.com/incanter/incanter/wiki/Sample-Plots-in-Incanter#line - vectorz-clj
https://github.com/mikera/vectorz-clj - vectorz – Examples
https://github.com/mikera/vectorz-clj/wiki/Examples - Basic Vector and Matrix Operations in Julia: Quick Reference and Examples
https://queirozf.com/entries/basic-vector-and-matrix-operations-in-julia-quick-reference-and-examples - Vectors and matrices in Julia
https://fncbook.github.io/v1.0/linsys/demos/matrices-julia.html - Array vs Matrix in R Programming
https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/ - Concurrency (computer science)
https://en.wikipedia.org/wiki/Category:Concurrency_%28computer_science%29 - Koprogram
https://cs.wikipedia.org/wiki/Koprogram - Coroutine
https://en.wikipedia.org/wiki/Coroutine - Coroutines in C
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - S-expression (Wikipedia)
https://en.wikipedia.org/wiki/S-expression - S-Expressions (Rosetta Code)
http://rosettacode.org/wiki/S-Expressions - Introducing Julia/Metaprogramming
https://en.wikibooks.org/wiki/Introducing_Julia/Metaprogramming - Tutorial for the Common Lisp Loop Macro
http://www.ai.sri.com/pkarp/loop.html - Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Clojure Macros and Metaprogramming
http://clojure-doc.org/articles/language/macros.html - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - CS 2101 Parallel Computing with Julia
https://www.coursehero.com/file/11508091/CS-2101-Parallel-Computing-with-Julia/ - Julia By Example
https://samuelcolvin.github.io/JuliaByExample/ - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - 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/?area=interpreters - 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/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.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/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - Introducing Julia/Functions
https://en.wikibooks.org/wiki/Introducing_Julia/Functions - Functions (Julia documentation)
https://docs.julialang.org/en/v1/manual/functions/ - Evaluate binomial coefficients
http://rosettacode.org/wiki/Evaluate_binomial_coefficients - Ackermann function
http://rosettacode.org/wiki/Ackermann_function - Julia (front page)
http://julialang.org/ - Julia – dokumentace
http://docs.julialang.org/ - Julia – repositář na GitHubu
https://github.com/JuliaLang/julia - Julia (programming language)
https://en.wikipedia.org/wiki/Julia_%28programming_language%29 - IJulia
https://github.com/JuliaLang/IJulia.jl - Introducing Julia
https://en.wikibooks.org/wiki/Introducing_Julia - Julia: the REPL
https://en.wikibooks.org/wiki/Introducing_Julia/The_REPL - Month of Julia
https://github.com/DataWookie/MonthOfJulia - Learn X in Y minutes (where X=Julia)
https://learnxinyminutes.com/docs/julia/ - New Julia language seeks to be the C for scientists
http://www.infoworld.com/article/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html - Julia: A Fast Dynamic Language for Technical Computing
http://karpinski.org/publications/2012/julia-a-fast-dynamic-language - The LLVM Compiler Infrastructure
http://llvm.org/ - Julia: benchmarks
http://julialang.org/benchmarks/ - Type system
https://en.wikipedia.org/wiki/Type_system - Half-precision floating-point format
https://en.wikipedia.org/wiki/Half-precision_floating-point_format - Dartmouth BASIC
https://en.wikipedia.org/wiki/Dartmouth_BASIC - BASIC 4th Edition
http://www.bitsavers.org/pdf/dartmouth/BASIC_4th_Edition_Jan68.pdf - VECTRAN
https://encyclopedia2.thefreedictionary.com/VECTRAN - Comparison of programming languages (array)
https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(array) - BASIC at 50
https://www.dartmouth.edu/basicfifty/commands.html - BBC Basic – arrays
http://www.riscos.com/support/developers/bbcbasic/part2/arrays.html - Datová struktura
https://cs.wikipedia.org/wiki/Datov%C3%A1_struktura - SIMD instrukce využívané v moderních mikroprocesorech řady x86
https://www.root.cz/clanky/simd-instrukce-vyuzivane-v-modernich-mikroprocesorech-rady-x86/ - SIMD instrukce v moderních mikroprocesorech řady x86 (2.část: SSE)
https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–2-cast-sse/ - SIMD instrukce v moderních mikroprocesorech řady x86 (3.část: SSE2)
https://www.root.cz/clanky/simd-instrukce-v-modernich-mikroprocesorech-rady-x86–3-cast-sse2/ - Inductive type
https://en.wikipedia.org/wiki/Inductive_type - JuliaMono, a font for programming
https://github.com/cormullion/juliamono - It’s arrays all the way down
https://xpqz.github.io/learnapl/array.html - APL vs BQN vs J vs Q vs NumPy vs Julia vs R
https://www.youtube.com/watch?v=8ynsN4nJxzU - Trainspotting (APL)
https://xpqz.github.io/learnapl/tacit.html - Train Spotting in Dyalog APL – Dyalog Webinar with Richard Park
https://www.youtube.com/watch?v=Enlh5qwwDuY