Hlavní navigace

Specializované jazyky pro práci s N-dimenzionálními poli: jazyk J

9. 12. 2021
Doba čtení: 41 minut

Sdílet

 Autor: Depositphotos
Zatímco minule jsme se zabývali především univerzálními jazyky, dnes se zaměříme na programovací jazyk J, který je přímo určen pro práci s poli jedná se o skvělý doménově specifický jazyk.

Obsah

1. Specializované jazyky pro práci s N-dimenzionálními poli: jazyk J

2. Od APL k programovacímu jazyku J

3. Překlad interpretru jazyka J

4. Zápis programů v jazyku J

5. Atomy a N-dimenzionální pole v programovacím jazyku J

6. Primitivní funkce jazyka J

7. Pravidla pro pojmenování primitivních funkcí

8. Vyhodnocování aritmetických a logických výrazů

9. Operace s vektory v programovacím jazyku J

10. Základní aritmetické funkce aplikované na vektory

11. Výběr prvků z vektorů (selektory)

12. Konstrukce vektorů založená na generátorech (indexů)

13. Matice

14. Výběr prvků z matic

15. Predikáty pracující s atomy, vektory i maticemi

16. Různé způsoby spojení polí

17. Pokročilejší operace nad poli

18. Operátor / (reduce)

19. Dyadická forma operátoru /

20. Odkazy na Internetu

1. Specializované jazyky pro práci s N-dimenzionálními poli: jazyk J

„It is easier to learn enough Basic or Java to solve trivial problems, but it is easier to learn enough J to solve more interesting and challenging problems.“

Na úvodní článek o programovacích jazycích určených pro provádění operací s poli dnes navážeme. Zatímco minule jsme se zabývali především univerzálními jazyky, dnes se zaměříme na programovací jazyk J, který je přímo určen pro práci s poli (a lze ho považovat za skvělý doménově specifický jazyk). Jedná se o ideového pokračovatele jazyka APL, takže v žádném případě nečekejte „mainstreamový“ přístup. Je tomu naopak, protože prakticky všechny operace a funkce se zapisují odlišně, než je tomu v běžnějších programovacích jazycích. V rámci dnešního článku si taktéž odpovíme na dotazy zmíněné minule:

  1. Kolik dimenzí může pole mít? Typicky 1 a 2, někdy i více.
  2. Začínají indexy prvků od 0, 1 či je první index volitelný?
  3. Jsou podporována obdélníková pole nebo nepravidelná pole?
  4. Jsou jednotlivé osy na sobě nezávislé? (což vylučuje nepravidelná pole)
  5. Je možné indexy na jednotlivých osách pojmenovat? (a vytvořit tak vlastně datový rámec)
  6. Jedná se o homogenní nebo o heterogenní datovou strukturu? Homogenní struktura může uchovávat prvky jediného (typicky předem definovaného) typu, zatímco v heterogenní struktuře mohou být umístěny prvky různých typů.
  7. Je nějakým způsobem omezen datový typ prvků pole? (například jen na celá čísla a čísla reálná).
  8. Lze prvky pole měnit (mutable) nebo je pole neměnitelné (immutable).
  9. Pokud jsou pole heterogenní a měnitelná, může prvek pole obsahovat to samé pole?
  10. Obsahuje pole přímo hodnoty prvků nebo jen reference na prvky?
  11. Jsou prvky v poli uloženy v operační paměti za sebou nebo se jedná o strukturu s ukazateli?
  12. Jsou prvky v 2D poli uloženy po řádcích nebo po sloupcích? (C versus Fortran).
  13. Lze měnit tvar (shape) pole?
  14. Podporuje jazyk operace nad celými poli?
  15. Podporuje jazyk takzvaný broadcasting (aplikaci skaláru na všechny prvky pole atd.)?
  16. Jsou pole plnohodnotným datovým typem nebo speciální strukturou?
  17. Je podporován „literál typu pole“?
Poznámka: i když se to nezdá, spočívá největší nevýhoda programovacího jazyka J v tom, že pokud se vývojář seznámí se způsobem práce s poli v tomto jazyku, bude v běžných (mainstreamových) jazycích doslova trpět při řešení problémů z této oblasti.

2. Od APL k programovacímu jazyku J

„Real Programmers don't write in APL, unless the whole program can be written on one line“

Historie programovacího jazyka APL, s nímž jsme se seznámili již v tomto článku, se začala psát již v roce 1957. Právě tehdy Kenneth E. Iverson, který v té době pracoval na Harvardské universitě, navrhl zcela novou notaci určenou pro jednotný zápis matematických funkcí i pro tvorbu funkcí nových. Tato notace byla prakticky ve všech ohledech odlišná od zavedené notace (resp. přesněji řečeno) notací, které se v matematice používaly. V roce 1962 byla tato notace popsána v knize nazvané „A Programming Language“ a (což původně vlastně ani nebylo plánováno) o několik let později se začaly objevovat skutečné interpretry i překladače programovacího jazyka používajícího stejné symboly, jaké popsal Iverson ve své knize. Konkrétně se jednalo o jazyk nazvaný IVSYS, který byl implementovaný v roce 1966 (což ovšem ještě nebyl skutečný APL, který byl následován jazykem APL\360 z roku 1966 a poté jazykem APL\1130 z roku 1968, jenž pracoval na počítači IBM 1130.

Kenneth Iverson se rozvoji a propagaci jazyka APL aktivně věnoval více než 20 let, za což mu poprávu byla v roce 1979 udělena Turingova cena (Turing Award). Později Iverson navrhl programovací jazyk J, v němž se místo speciálních symbolů používají pouze znaky obsažené v ASCII tabulce (viz další kapitoly s podrobnějšími informacemi). Vraťme se však k APL. Specifikace tohoto programovacího jazyka se od poloviny šedesátých let minulého století několikrát změnila (rozšířila). Jedním z nejvíce důležitých rozšíření je APL2 od J. Browna z IBM, které do jazyka zavedlo podporu pro rekurzivní datové struktury (tedy, jak uvidíme dále, pro pole jako prvky jiných polí, což je mimochodem dále zobecněno v jazyku BQN a vlastně i v jazyku J). Většina dnešních implementací tohoto programovacího jazyka se snaží dodržovat specifikaci APL2, i když je jazyk dále rozšiřován (například v APLX verze 4 byla přidána podpora pro objektově orientované programování, i když v poněkud jiné podobě, než ji známe z mainstreamových programovacích jazyků). Z moderních implementací APL se pak musíme zmínit o komerčním projektu Dyalog APL.

Nesmíme ovšem ignorovat fakt, že i přes všechny zajímavé rysy má programovací jazyk APL i několik nectností, ostatně jako každý programovací jazyk, který vznikl na samotném začátku vývoje interpretrů a překladačů, tj. v době, kdy ještě nebyla teorie překladačů tak rozvinutá jako v pozdějších letech (nejvíce byla neexistence teorie překladačů patrná u prvního překladače Fortranu vytvořeného firmou IBM, jehož vývoj by byl při uplatnění dnešních znalostí mnohem rychlejší, levnější, samozřejmě i samotný jazyk by vypadal poněkud jinak). Už při letmém pohledu na algoritmy, resp. celé programy napsané v programovacím jazyce APL, je zřejmé, že se v něm používá velké množství symbolů, které se nenachází ve znakové sadě ASCII, což je sice velmi unikátní vlastnost (právě proto mnozí v APL programují čistě pro radost z vizuální podoby programů), ale způsobuje poměrně velké problémy, jak při zápisu programů (rozložení znaků na klávesnici), tak i při jejich úpravách, prezentaci na Internetu (zdaleka ne všechny fonty obsahují všechny požadované symboly) atd.

Poznámka: ve skutečnosti jsou tyto problémy do značné míry již vyřešeny, protože znaky jazyka APL byl přidány do Unicode.

Některé nedostatky programovacího jazyka APL jsou obsaženy i v jeho samotné sémantice, což je mnohem závažnější, než „pouhý“ vzhled zápisu nebo problémy při tisku nebo prezentacích. Jmenujme například zápis řídicích struktur s využitím čísel řádků (podobně jako v BASICu, i když čísla řádků jsou v APL pro každou funkci lokální, což například znemožňuje provádět skoky dovnitř funkcí o odstraňuje vzájemnou závislost jednotlivých funkcí). A taktéž se ukázalo, že by bylo vhodné, aby byl do mnohem větší míry podporován tacit programming, jímž jsme se zabývali v samostatném článku. Z výše uvedených důvodů otec jazyka APL (již zmiňovaný Kenneth Iverson) na počátku devadesátých let minulého století navrhl nový programovací jazyk nazvaný jednoduše J, který některé výše zmíněné nedostatky jazyka APL odstranil a navíc tento nový programovací jazyk rozšířil o některé důležité nové rysy, primitivní funkce i operátory. V dalších kapitolách si stručně popíšeme zejména ty vlastnosti jazyka J, které souvisí se zpracováním polí a vůbec k přístupu k této velmi důležité datové struktuře.

Poznámka: na tomto místě je pro úplnost nutno dodat, že moderní dialekty jazyka APL už vyřešily většinu výše zmíněných problémů. Moderní APL se tedy v tomto ohledu přiblížilo k jazyku J, kterým se budeme zabývat dnes (což se týká i podpory pro tacit programming apod.).

3. Překlad interpretru jazyka J

Na stránce http://www.jsoftware.com jsou nabízeny balíčky s interpretrem jazyka J určené pro všechny tři nejrozšířenější desktopové operační systémy. Po instalaci (která v případě Linuxu spočívá v prostém spuštění staženého skriptu s parametrem -install) se nainstaluje jak interpret programovacího jazyka J (představovaného knihovnou libj.so popř. j.dll), tak i konzolové (řádkové) rozhraní k interpretru (jconsole) a vývojové prostředí naprogramované původně v Javě (jwd), dnes dostupné přes webové rozhraní. Pro odzkoušení demonstračních programů postačuje spustit řádkové rozhraní interpretru jazyka J z terminálu resp. z konzole – jedná se o program nazvaný jconsole.

Poznámka: pozor – tento program je nutné spustit s uvedením cesty, například ./jconsole, v opačném případě by se mohla spustit stejnojmenná utilita dodávaná spolu s JDK.

Protože se však nacházíme na Rootu, ukážeme si, jakým způsobem je možné konzoli s interpretrem programovacího jazyka J přeložit přímo ze zdrojových kódů. Projekt s jazykem J totiž po velmi dlouhé době, kdy se jednalo o projekt dosti izolovaný od ostatního světa a s relativně uzavřenou a malou komunitou, nabízí zdrojové kódy dostupné přes GitHub a přeložitelné jednoduše z příkazové řádky.

Celý postup překladu je jednoduchý. Nejdříve je nutné naklonovat repositář se zdrojovými kódy (kombinace C a J):

$ git clone git@github.com:jsoftware/jsource.git

Dále se v podadresáři make2 spustí skript nazvaný build_all:

$ cd make2
$ ./build_all

Překlad je ve výchozím nastavení prováděn v jediném vláknu, ovšem ani tak netrvá dlouho. Po dokončení činnosti skriptu build_all by se měl v podadresáři bin/linux/j64avx objevit jak interpret (představovaný knihovnou), tak i aplikace jconsole, která interpret jazyka J spustí:

$ cd ..

O výsledku překladu se snadno přesvědčíme:

$ ls -la bin/linux/j64avx/
 
total 4192
drwxrwxr-x 2 ptisnovs ptisnovs     100 Dec  6 19:54 .
drwxrwxr-x 3 ptisnovs ptisnovs      60 Dec  6 19:46 ..
-rwxrwxr-x 1 ptisnovs ptisnovs   57184 Dec  6 19:52 jconsole
-rwxrwxr-x 1 ptisnovs ptisnovs 4201104 Dec  6 19:54 libj.so
-rwxrwxr-x 1 ptisnovs ptisnovs   31984 Dec  6 19:54 libtsdll.so

Samotný interpret je možné spustit takto:

$ bin/linux/j64avx/jconsole
j_lang1_4

Obrázek 1: Původní vývojové prostředí (vytvořené v Javě) dodávané spolu s interpretrem programovacího jazyka J.

4. Zápis programů v jazyku J

Nyní, když již máme k dispozici interpret jazyka J, si můžeme prakticky vyzkoušet některé jeho vlastnosti. Nejprve si řekneme, jak vypadá struktura zapsaných programů. Způsob zápisu programů v programovacím jazyku J se v mnoha ohledech podobá zápisu používaném v programovacím jazyku APL. Na každém textovém řádku je (tedy většinou – pokud je autor při smyslech) zapsán jeden výraz, který je interpretrem ihned po svém zápisu zpracován a vyhodnocen. V případě, že je výraz zapsaný v interaktivním režimu (například z aplikace jconsole), je výsledek výrazu ihned po jeho vyhodnocení vytištěn na terminál – právě tento způsob práce, který je ostatně společný většině interpretovaných programovacích jazyků, budeme používat ve všech následujících demonstračních příkladech (příkazy zadávané uživatelem jsou pro odlišení zpráv interpretru odsazeny od levého okraje, což je implicitní chování nástroje jconsole; taktéž jsou příkazy zadávané uživatelem zvýrazněny pomocí tučného písma).

Zajímavý a nutno říci, že i dosti neobvyklý je i zápis komentářů. V mnoha programovacích jazycích se pro označení začátku jednořádkových komentářů používá speciální znak či znaky. Například v C++, Javě či JavaScriptu se jedná o dvojici znaků „//“ (nebo o „komentářové závorky“ /* a */ pro víceřádkové komentáře) a v shellu i Pythonu o jeden znak „#“. V programovacím jazyku J je ovšem vše jinak. Zde se totiž začátek komentáře označuje trojicí znaků „NB.“. Veškerý text na řádku zapsaný za těmito znaky je interpretrem ignorován. To tedy znamená, že můžeme psát:

   NB. komentar umisteny na zacatku programoveho radku
 
   1+2*3 NB. komentar umisteny za vyrazem, samotny vyraz se vykona a vypise se jeho vysledek
7
   NB. tento vyraz se nevykona, nebot je soucasti komentare: 1+2*3
Poznámka: způsob zápisu komentářů v různých programovacích jazycích je shrnut na stránce http://www.gavilan.edu/csis/lan­guages/comments.html.

5. Atomy a N-dimenzionální pole v programovacím jazyku J

V programovacím jazyku J se primárně rozlišují dvě skupiny typů hodnot. První skupinu tvoří atomy (atom), druhou skupinu pak pole (array). Atomy neboli skaláry je skupina tvořená třemi datovými typy:

  1. numerický typ
  2. znakový typ

Nejzajímavějším atomárním neboli skalárním datovým typem je box. Tento název je velmi přiléhavý, protože se skutečně jedná o jakýsi obal, který může obsahovat libovolnou jinou hodnotu – ať již skalární, tak i pole. Díky existenci boxů je sice typový systém programovacího jazyka J poměrně flexibilní, ovšem ukazuje se, že komplikuje práci s poli. Proto je například v jazyku BQN, který je ideovým pokračovatelem APL i J, použit odlišný typový systém.

Ústředním prvkem jazyka J jsou ovšem – jak lze snadno uhodnout – pole. 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. Os přitom může být (prakticky) libovolný počet – J tedy nemá žádná omezení, která jsme mohli vidět například v BBC BASICU či v Dartmouth BASICu. Další důležitou vlastností polí je, že jsou homogenní, tj. obsahují prvky stejného typu (nebo boxy). A navíc jsou pole měnitelná, neboli mutable – prvky polí je tedy možné modifikovat. Od jazyka APL se J odlišuje v tom, že se prvky podél os indexují od nuly a nikoli od jedničky, což si ukážeme na demonstračních příkladech.

Pole s počtem dimenzí (resp. os) 1 až 3 mají v jazyku J specifické názvy:

Počet dimenzí/os Název pole
1 list
2 table
3 brick
Poznámka: pozor na to, že seznam s jediným prvkem se striktně odlišuje od skaláru!

Pole s jednou, dvěma a třemi osami lze vytvořit funkcí i., která zhruba odpovídá generátoru range z Pythonu, ovšem s tím, rozdílem, že počet os a tvar pole je volitelný:

   i. 3
0 1 2
 
   i. 2 3
0 1 2
3 4 5
 
   i. 2 3 4
 0  1  2  3
 4  5  6  7
 8  9 10 11
 
12 13 14 15
16 17 18 19
20 21 22 23

Přečtení tvaru pole – seznamu obsahujícího počet atomů podél každé osy funkcí $ (shape):

   $ 42
 
 
   $ 1 2 3
3
 
   $ i. 2 3
2 3
 
   $ i. 2 3 4
2 3 4
 
   $ (<'abc'),(<1;2;3),(<1;2)
3

Získání počtu os monadickou funkcí # (rank) zkombinovanou s #:

   # $ 42
0
 
   # $ 1 2 3
1
 
   # $ 1 2 3 4
1
 
   # $ i. 2 3
2
 
   # $ i. 2 3 4
3
 
   # $ (<'abc'),(<1;2;3),(<1;2)
1

Víme již, že pole musí být homogenní, což je podmínka, kterou lze „obejít“ použitím boxů. Termínem boxing se označuje vytvoření atomu (boxu), jehož obsah je prakticky libovolný, tedy může se vytvořit homogenní pole boxů. Samozřejmě jsou ovšem nutná nějaká omezení, protože box není numerickým typem a tudíž ho nelze použít v aritmetických operacích. Box je ovšem možné otevřít (open) a získat tak jeho obsah.

Vytvoření boxu – zabalení hodnoty:

   (<'abc')
+---+
|abc|
+---+
Poznámka: už víte, proč se používá termín „box“?

Spojení dvou boxů do vektoru:

   (<'abc'),(<1 2 3)
+---+-----+
|abc|1 2 3|
+---+-----+

Box jako prvek pole s boxy:

   (<'abc'),(<1 2 3),(<1;2)
+---+-----+-----+
|abc|1 2 3|+-+-+|
|   |     ||1|2||
|   |     |+-+-+|
+---+-----+-----+
 
   (<'abc'),(<1;2;3),(<1;2)
+---+-------+-----+
|abc|+-+-+-+|+-+-+|
|   ||1|2|3|||1|2||
|   |+-+-+-+|+-+-+|
+---+-------+-----+

A konečně si ukažme funkci amend, která dokáže změnit obsah vybraného prvku pole:

   100 (< 2) } i. 10
0 1 100 3 4 5 6 7 8 9

6. Primitivní funkce jazyka J

Podobně jako v programovacím jazyku APL, nalezneme i v dnes popisovaném jazyku J poměrně velké množství primitivních (neboli základních) funkcí. Ty však nejsou reprezentovány speciálními symboly („hieroglyfy“), ale jedním nebo větším množstvím nealfanumerických ASCII znaků, takže jejich zápis i editace je jednodušší, než tomu bylo v případě APL (na druhou stranu nevypadají zapsané algoritmy tak efektně a možná i elegantně :-). Primitivní funkce mohou akceptovat buď jeden parametr (to jsou takzvané monadické funkce) nebo parametry dva (funkce dyadické). Název monadických funkcí je uveden v prefixové podobě, tj. vždy před svým parametrem, zatímco dyadické funkce jsou zapisovány v podobě infixové – mezi oběma parametry, čímž se efektivně v mnoha případech eliminuje nutnost použití závorek (ty jsou ovšem taktéž podporovány). Znaky, kterými jsou primitivní funkce pojmenovány, jsou většinou použity minimálně dvakrát – jednou pro zápis monadické funkce, podruhé pro zápis funkce dyadické, jejíž význam bývá v menší či větší míře podobný příslušné monadické funkci.

Poznámka: na monadické i dyadické funkce se taktéž můžeme dívat jako na operátory, protože se ostatně jako operátory zapisují – buď před operand nebo mezi oba operandy.
j_lang1_5

Obrázek 2: Interpret jazyka J je poměrně bohatě vybaven i možností práce s různými typy grafů, což je (spolu s podporou snadné práce s vektory a maticemi) jeden z důvodů poměrně velké oblíbenosti tohoto jazyka mezi inženýry.

7. Pravidla pro pojmenování primitivních funkcí

Kromě použití stejného znaku pro pojmenování nějaké primitivní monadické a současně i dyadické funkce může být navíc za znakem představujícím jméno primitivní funkce uveden symbol „:“ (dvojtečka) nebo „.“ (tečka), což v praxi znamená, že tentýž znak může být ve skutečnosti použit pro pojmenování až šesti různých primitivních funkcí. Například pro znak „<“ existuje celkem pět různých forem, které byly Iversonem a jeho kolegy při návrhu jazyka J zvoleny takovým způsobem, aby buď přímo odpovídaly významu tohoto znaku v matematickém zápisu, nebo měly alespoň logicky podobný význam. Zmíněný znak je (nejenom) v matematice spojen se slovem „menší“, takže je použit i pro implementaci funkce vyhledání minima či dekrementaci/zmenšení operandu o jedničku, jak je to ostatně patrné z následujících výrazů a jejich výsledku po vyhodnocení interpretrem programovacího jazyka J (v příkladech jsou jako parametry použity i vektory):

   NB. dyadicka funkce <
   NB. porovnani dvou hodnot na relaci "mensi nez"
   1 < 2
1
   2 < 2
0
 
   NB. porovnavat lze i slozky vektoru, vysledkem bude bitovy vektor
   1 2 3 < 3 2 1
1 0 0
 
   NB. Dyadicka funkce ukoncena dvojteckou
   NB. porovnani dvou hodnot na relaci "mensi nebo rovno"
   1 <: 2
1
   2 <: 2
1
   NB. opet lze porovnavat i slozky vektoru
   1 2 3 <: 3 2 1
1 1 0
 
   NB. dyadicka funkce ukoncena teckou
   NB. vrati mensi operand (parametr) = odpovida funkci min
   1 <. 2
1
   2 <. 1
1
   NB. porovnani prislusnych slozek vektoru a vraceni mensi z nich
   1 2 1 <: 3 2 1
1 2 1
 
   NB. monadicka funkce ukoncena teckou
   NB. zaokrouhleni smerem dolu (obdoba ceckove funkce floor)
   <. 2.5
2
   <. 2.9
2
 
   NB. tuto funkci lze samozrejme volat i na vektory
   <. 1.9 2.0 2.1 2.9
1 2 2 2
 
   NB. monadicka funkce ukoncena dvojteckou
   NB. operace dekrementace (obdoba ceckoveho operatoru --)
   <: 1
0
   <: 10
9
   <: 1 2 3
0 1 2
   <: 0 1 2
_1 0 1
Poznámka: podobných funkcí uvidíme v dalším textu ještě mnoho.

8. Vyhodnocování aritmetických a logických výrazů

Aritmetické a logické výrazy, které většinou tvoří nejdůležitější součást všech programů zapisovaných v jazyku J, se vyhodnocují stejným způsobem, jako v již popsaném programovacím jazyku APL, tj. zprava doleva bez toho, aby některé funkce měly vyšší prioritu než funkce jiné. Funkce se zapisují stejným způsobem jako v jiných jazycích prefixové a infixové operátory, tj. buď mezi oba argumenty (operandy) při volání dyadických funkcí nebo před jediný argument v případě, že se volá funkce monadická. V případě, že je zapotřebí změnit pořadí volání funkcí, lze k tomuto účelu použít obligátní kulaté závorky. V jazyku J je k dispozici pět základních aritmetických funkcí, které jsou vypsány v tabulce pod odstavcem (povšimněte si především odlišného způsobu zápisu funkce podílu dvou hodnot). Do tabulky jsou pro úplnost dopsány i tři další funkce pro výpočet mocniny, odmocniny a faktoriálu. Způsob použití těchto funkcí i způsob úpravy priority (pořadí volání) je patrný z demonstračních příkladů uvedených pod tabulkou.

Znak funkce Monadická funkce Dyadická funkce
+ negace imaginární složky komplexního čísla součet (skalárů, vektorů, matic…)
negace rozdíl
* vrací znaménko součin
% převrácená hodnota podíl
| absolutní hodnota zbytek
^   umocnění xy
*: druhá mocnina x2  
%: druhá odmocnina x1/2  
! faktoriál  

Příklad použití operací:

   NB. priorita je vždy zprava doleva
   1+2*3
7
 
   NB. specifikace priority zavorkami
   1+(2*3)
7
 
   NB. specifikace priority zavorkami
   (1+2)*3
9
 
   NB. funkce jsou vyhodnocovany zprava doleva,
   NB. tj. zde nejdrive soucet a teprve pote soucin
   3*2+1
9
 
   NB. specifikace priority zavorkami
   3*(2+1)
9
 
   NB. zmena poradi vyhodnoceni funkci pomoci zavorek
   (3*2)+1
7
 
   NB. zaporna cisla jsou zapisovana se symbolem _
   10-20
_10
 
   NB. podil se zapisuje symbolem %
   42%3
14
 
   NB. druha mocnina je zapisovana pomoci monadicke funkce *:
   *: 10
100
 
   NB. vypocet prevracene (reciproke) hodnoty
   % 3
0.33333
 
   NB. vypocet desate mocniny
   2^10
1024
 
   NB. zaporny exponent
   2^(_10)
0.000976562
 
   NB. aritmeticke funkce lze pouzit i pro soucet vektoru
   1 2 3 + 4 5 6
5 7 9
 
   NB. vydeleni skalarni hodnoty postupne vsemi slozkami vektoru
   42 % 2 3 4
21 14 10.5
 
   NB. kazda slozka vektoru je umocnena na desatou
   2 3 4 ^ 10
1024 59049 1.04858e6
 
   NB. vypocet druhych mocnin vsech slozek vektoru
   *: 1 2 3 4
1 4 9 16
 
   NB. vypocet faktorialu (samozrejme je pouzit prefixovy zapis)
   !6
720
 
   !170
7.25742e306
 
   NB. tento zapis si podrobneji vysvetlime pozdeji
   !i.10
1 1 2 6 24 120 720 5040 40320 362880

9. Operace s vektory v programovacím jazyku J

Jak jsme se již dozvěděli z úvodního textu, je programovací jazyk J, ostatně podobně jako jeho ideový předchůdce APL, určen především pro tvorbu aplikací, v nichž se zpracovávají data uložená ve vektorech, maticích či polích s větším počtem dimenzí (může se jednat například o hierarchické mřížky atd., a to mj. i díky možnosti použít boxing). Z tohoto důvodu je jazyk J vybaven jak jednoduchou syntaxí určenou pro zápis vektorů a matic, tak i sadou primitivních (základních) funkcí, pomocí nichž lze nad vektory i maticemi provádět různé operace. Nejprve si popíšeme primitivní funkce určené pro vytváření i další práci s vektory, které jsou vypsány v následující tabulce.

Poznámka: v rozporu s oficiální dokumentací jazyka J používám termín vektor, i když v J se používá termín seznam (list). To je však zavádějící vzhledem k tomu, jaký má seznam význam v jiných programovacích jazycích.

U všech popisovaných funkcí bude uvedena i informace o tom, zda se jedná o funkci monadickou (tj. s jedním parametrem zapisovaným za symbol funkce) či dyadickou (s dvojicí parametrů, z nichž první se zapisuje před a druhý za symbol funkce). Tato informace je v případě jazyků JAPL velmi důležitá, protože již víme, že stejný symbol může být použit pro pojmenování dvou primitivních funkcí lišících se „pouze“ počtem svých parametrů:

Symbol funkce Forma funkce Popis funkce (význam)
+ – * % dyadická základní aritmetické operace prováděné nad dvojicí vektorů na korespondujících prvcích (též prováděné nad skalárem a vektorem)
< <: > >: = ~: dyadická porovnání korespondujících prvků dvou vektorů
# monadická vrací délku vektoru
# dyadická kopie prvků vektoru představovaného druhým parametrem
{ dyadická výběr prvku či více prvků z vektoru na základě indexů vybíraných prvků
{. dyadická výběr prvních n prvků z vektoru
}. dyadická výběr posledních délka-n prvků vektoru (= odstranění prvních n prvků)
, dyadická spojení dvou vektorů či vektoru se skalárem
/: monadická setřídění prvků vektoru sestupně (funkce vrací indexy prvků, ne jejich hodnoty)
\: monadická setřídění prvků vektoru vzestupně (funkce též vrací indexy prvků, ne jejich hodnoty)
i. monadická vytváří seznam (vektor) obsahující řadu čísel začínající nulou, popř. prázdný vektor
i: monadická vytváří seznam (vektor) obsahující čísla on -n do n, kde n je parametr funkce
p. monadická výpočet kořenů polynomu reprezentovaného vektorem obsahujícím koeficienty ai
Poznámka: první čtyři funkce už byly zmíněny v souvislosti s operacemi prováděnými nad skaláry. Platí zde stále stejná pravidla – vyhodnocování je prováděno zprava doleva, čímž je automaticky určena i priorita operací. Tu lze změnit jen pomocí kulatých závorek.

10. Základní aritmetické funkce aplikované na vektory

Základní aritmetické operace, se kterými jsme se již seznámili v předchozích kapitolách (aplikovaných na skaláry), je možné využít i při práci s vektory. V tomto případě se operace provádí vždy nad dvojicí odpovídajících prvků (dyadické funkce) popř. postupně pro všechny prvky vektoru (funkce monadické). Pokud nejsou délky vektorů shodné, nahlásí interpretr jazyka J chybu typu „length error“ (jen u několika specifických operací se délka kratšího vektoru „dorovná“ s vektorem delším):

   NB. Nejdříve vytvoříme tři proměnné
   NB. představující trojici vektorů (různé délky)
   x =: 1 2 3 4
   y =: 9 8 7 6
   z =: 11 12
 
   NB. Čtyři základní aritmetické operace
   NB. (součet, rozdíl, součin, podíl)
   NB. prováděné nad prvky vektorů
   x+y
10 10 10 10
 
   y-x
8 6 4 2
 
   x*y
9 16 21 24
 
   x%y
0.111111 0.25 0.428571 0.666667
 
   NB. Následující příkaz skončí s chybou
   NB. neboť délky vektorů (=počty jejich
   NB. prvků) nejsou shodné
   x+z
|length error
|   x    +z

Při použití aritmetických funkcí může být jedním z parametrů i skalární hodnota, která je aplikována na všechny prvky vektoru. Viz též následující demonstrační příklady:

   NB. Při volání aritmetických funkcí
   NB. je možné zkombinovat skalární hodnotu
   NB. s vektorem
   2 * x
2 4 6 8
 
   x * 2
2 4 6 8
 
   NB. Předchozí dva výrazy 2 * x a 2 * y
   NB. sice vrátily shodný výsledek, ale některé
   NB. další aritmetické operace nejsou
   NB. komutativní, například dělení:
   10 % x
10 5 3.33333 2.5
 
   x % 10
0.1 0.2 0.3 0.4

Následují dva příklady použití dalších funkcí, konkrétně dyadické exponenciální funkce a monadické funkce pro výpočet faktoriálu:

   NB. Při práci s vektory lze samozřejmě
   NB. použít i další primitivní funkce,
   NB. zde například funkci exponenciální
   x^y
1 256 2187 4096
 
   NB. Monadická funkce (výpočet faktoriálu)
   ! x
1 2 6 24

11. Výběr prvků z vektorů (selektory)

Další důležitou a současně i velmi často používanou skupinou základních (primitivních) funkcí určených pro práci s vektory jsou funkce, které umožňují z vektoru vybrat hodnoty některých prvků. Jedná se o rozšíření funkcí „take“ a „drop“, se kterými jsme se již seznámili při popisu programovacího jazyka APL, ovšem s tím rozdílem, že prvky vektorů jsou v případě jazyka J číslovány od nuly, tj. první prvek má index roven 0 a index posledního prvku je roven délce vektoru-1 (což je mimochodem poměrně zvláštní ústupek mainstreamu – v jiných ohledech je J tak vzdálen od mainstreamu tak, jak je to jen možné). Dále se v této skupině nachází funkce umožňující provést spojení dvou vektorů, která se zapisuje pomocí ASCII znaku „,“ – čárka. V aplikacích se poměrně často vyskytuje i funkce vracející délku vektoru (ASCII znak „#“). V případě matic či polí tato funkce vrací rozměr všech jejich dimenzí, což si ukážeme v navazujících kapitolách.

Základní způsoby použití selektorů si pochopitelně opět ukážeme na demonstračních příkladech:

   NB. Nejdříve opět vytvoříme tři proměnné
   NB. představující trojici vektorů
   x =: 1 2 3 4
   y =: 9 8 7 6
   z =: 11 12
 
   NB. Zjistíme délky (počet prvků) všech vektorů
   #x
4
   #y
4
   #z
2
 
   NB. Spojení vektorů pomocí primitivní
   NB. funkce , (čárka)
   w =: x,y,z
   w
1 2 3 4 9 8 7 6 11 12
 
   NB. Jak je výsledný vektor w dlouhý?
   #w
10
 
   NB. Výběr pátého prvku (s indexem 4)
   4 { w
9
 
   NB. Výběr pátého, šestého a sedmého
   NB. prvku vektoru w (obdoba funkce take)
   4 5 6 { w
9 8 7
 
   NB. Výběr prvních čtyř prvků vektoru
   4 {. w
1 2 3 4
 
   NB. Vrácení vektoru BEZ jeho prvních
   NB. čtyř prvků (obdoba funkce drop)
   4 }. w
9 8 7 6 11 12

Funkce pro výběr prvků mají svoje názvy:

Funkce Forma Jméno
{. dyadická take
}. dyadická drop
{. monadická head
}. monadická behead
{: monadická tail
}: monadická curtail

Funkce take vrátí prvních n prvků vektoru. V případě potřeby je vektor zprava doplněn nulami. Lze použít i záporný počet prvků:

   i. 10
0 1 2 3 4 5 6 7 8 9
 
   3 {. i. 10
0 1 2
 
   30 {. i. 10
0 1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 
   _5 {. i. 10
5 6 7 8 9

Funkce drop vrátí vektor bez prvních n prvků. Lze použít i záporný počet prvků:

   3 }. i. 10
3 4 5 6 7 8 9
 
   _3 }. i. 10
0 1 2 3 4 5 6

Monadická funkce head vrátí první prvek vektoru:

   {. i. 10
0

Funkce behead vrátí vektor bez prvního prvku:

   }. i. 10
1 2 3 4 5 6 7 8 9

Monadická funkce tail vrátí poslední prvek vektoru:

   {: i. 10
9

A konečně funkce curtail vrátí vektor bez posledního prvku:

   }: i. 10
0 1 2 3 4 5 6 7 8

12. Konstrukce vektorů založená na generátorech (indexů)

Nyní si ve stručnosti ukážeme způsob použití takzvaných generátorů indexů představovaných primitivními funkcemi zapisovanými pomocí symbolů i. a i:. Jedná se o velmi užitečné a v praxi často využívané funkce, které odpovídají primitivní funkci ι, s níž jsme se již seznámili při popisu programovacího jazyka APL, ovšem s tím podstatným rozdílem, že první číslo generované funkcí i. má hodnotu nula, nikoli jedna, a poslední číslo má hodnotu n-1 a nikoli n (to souvisí s tím, že v programovacím jazyce J jsou položky vektorů číslovány–indexovány od nuly, podobně jako například v programovacích jazycích C, C++ či Java – viz též předchozí kapitolu věnovanou indexování). Povšimněte si taktéž, že se pomocí funkce i. dá vytvořit velké množství různých (nejenom) aritmetických řad, takže pro tyto účely není nutné používat programové smyčky. Navíc mohou být primitivní funkce i. a i: součástí nějakého složitějšího výrazu, čehož se při psaní aplikací poměrně často využívá, například při programové tvorbě matic (jednotková matice, trojúhelníková matice atd.).

Poznámka: zde je nutno upozornit na to, že se vektor skutečně vytvoří – funkce i. tedy není „líná“ tak, jako například generátory v Pythonu.
   NB. Základní použití generátoru indexů
   i. 10
0 1 2 3 4 5 6 7 8 9
 
   NB. Poměrně snadno můžeme dosáhnout toho,
   NB. aby se počáteční hodnota generované
   NB. číselné řady "posunula"
   20 + i. 10
20 21 22 23 24 25 26 27 28 29
 
   NB. Řada začínající hodnotou -10
   _10 + i. 10
_10 _9 _8 _7 _6 _5 _4 _3 _2 _1
 
   NB. Posun a současně i změna "kroku"
   NB. při generování číselné řady
   3 + 0.5 * i. 15
3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10
 
   NB. Mocninná řada čísla 2 vytvořená
   NB. bez použití programové smyčky
   2 ^ i. 10
1 2 4 8 16 32 64 128 256 512
 
   NB. Výpočet prvních faktoriálu prvních deseti
   NB. přirozených čísel a nuly.
   NB. (připomeňme si, že funkce se vyhodnocují
   NB.  zprava doleva, tj. nejdříve se vytvoří
   NB.  vektor čísel, na jehož prvky je aplikována
   NB.  primitivní funkce představující faktoriál)
   ! i. 10
1 1 2 6 24 120 720 5040 40320 362880
 
   NB. Pomocí primitivní funkce i: lze vygenerovat
   NB. číselnou řadu symetrickou okolo nuly
   i: 10
_10 _9 _8 _7 _6 _5 _4 _3 _2 _1 0 1 2 3 4 5 6 7 8 9 10
 
   NB. Změna kroku číselné řady
   2* i: 10
_20 _18 _16 _14 _12 _10 _8 _6 _4 _2 0 2 4 6 8 10 12 14 16 18 20
 
   NB. Opět výpočet mocnin čísla 2, tentokrát však
   NB. včetně záporných exponentů
   2^ i: 5
0.03125 0.0625 0.125 0.25 0.5 1 2 4 8 16 32
 
   NB. Vytvoření prázdného vektoru (jedna z nejčastěji
   NB. používaných možností tvorby prázdného vektoru)
   i. 0
 
 
   NB. Ovšem pozor: v následujícím případě
   NB. se vytvoří vektor obsahující jeden prvek
   i: 0
0
Poznámka: v předchozích ukázkách bylo poměrně dobře vidět, jak odlišný je přístup při řešení některých problémů v mainstreamových jazycích v porovnání s jazykem J. Například vytvoření mocninné řady o základu 2 atd. – vše bez nutnosti použití programových smyček.

Vektor s nulami se tvoří podobnou funkcí I.:

   I.1
0
 
   I.10
0 0 0 0 0 0 0 0 0 0

13. Matice

Práce s maticemi je v programovacím jazyku J stejně snadná jako práce s vektory. Základní funkci při práci s maticemi představuje funkce reshape zapisovaná pomocí symbolu $. Tato funkce má stejné vlastnosti jako funkce ρ zmiňovaná při popisu programovacího jazyka APL – v prvním parametru (zapisovaného nalevo od symbolu $) jsou uloženy rozměry matice, v parametru druhém (uváděném napravo od symbolu $) pak její jednotlivé prvky, typicky uložené ve vektoru nebo v jiné matici. Naopak monadická forma funkce $ vrací tvar pole (zde je symetrie dokonalá).

Poznámka: opět se zde odchyluji od oficiálních termínů používaných v jazyce J. Dvourozměrná pole by se totiž měla nazývat table, ovšem tento pojem má v jiných jazycích poněkud odlišný význam, takže zůstanu i přece jen zavedenějšího termínu matice (matrix).
   NB. Vytvoření nulové matice
   NB. o rozměrech 3x3 prvky
   3 3 $ 0
0 0 0
0 0 0
0 0 0
 
   NB. Vytvoření matice a současně
   NB. i nastavení hodnot jejích prvků
   3 2 $ 1 2 3 4 5 6
1 2
3 4
5 6
 
   NB. Použití generátoru indexů
   NB. při vytváření matice
   3 4 $ i. 12
0 1  2  3
4 5  6  7
8 9 10 11
 
   2 2 $ 0 1 2 3
0 1
2 3
 
   2 3 $ 0 1 2 3 4 5
0 1 2
3 4 5
 
   NB. Odlišný tvar, ovšem stejný obsah prvků
   3 2 $ 0 1 2 3 4 5
0 1
2 3
4 5

Dvourozměrná nečtvercová matice:

   2 3 $ i. 6
0 1 2
3 4 5

Trojrozměrná matice (brick):

   2 3 4 $ i. 24
 0  1  2  3
 4  5  6  7
 8  9 10 11
 
12 13 14 15
16 17 18 19
20 21 22 23

Odlišný tvar čtyřrozměrné matice:

   4 3 2 $ i. 24
 0  1
 2  3
 4  5
 
 6  7
 8  9
10 11
 
12 13
14 15
16 17
 
18 19
20 21
22 23

Zpětné získání tvaru pole pomocí monadické funkce $:

   $ 4 3 2 $ i. 24
4 3 2

Konstrukce prázdného pole:

   0 $ 10

Velmi důležitou „maticovou“ funkcí je funkce pro výpočet inverzní matice zapisovaná symbolem %.. S využitím této funkce lze například vypočítat soustavu n rovnic o n neznámých:

        x + 2y -3z = 15
        x + y + z = 12
       2x - y - z = 0

Nejprve vytvoříme příslušnou matici a zapíšeme do ní koeficienty (multiplikativní konstanty) uvedené před neznámými:

   NB. Prvky ležící na jednotlivých řádcích jsou
   NB. od sebe pro větší přehlednost odděleny
   NB. trojicí mezer.
   m =: 3 3 $   1 2 _3   1 1 1   2 _1 _1
   m
1  2 _3
1  1  1
2 _1 _1

S využitím funkce %.m lze snadno vypočítat inverzní matici:

   %.m
   0 0.333333   0.333333
 0.2 0.333333  _0.266667
_0.2 0.333333 _0.0666667

Po vynásobení inverzní matice vektorem obsahujícím pravé strany rovnic dostaneme kýžený výsledek – hodnoty neznámých x, y a z:

   15 12 0 %.m
4 7 1

14. Výběr prvků z matic

Pro výběr prvků z matic se používají stejné funkce, jako pro výběr prvků z vektorů. Pouze nesmíme zapomenout na to, že výběrem jedním indexem získáme z matice vektor.

Nejprve si zopakujeme způsob výběru prvků z vektoru:

Výběr prvků z vektoru s využitím indexu:

   0 { 5 6 7 8
5

Index prvního prvku je roven nule:

   1 { 5 6 7 8
6

Použití záporného indexu:

   _1 { 5 6 7 8
8

Použití záporného indexu:

   _2 { 5 6 7 8
7

Pozor na to, že funkce – není stejná jako znaménko _:

   -1 { 5 6 7 8
_6

Výběr více prvků z vektoru:

   0 2 3 { 5 6 7 8
5 7 8

Výběr více prvků z vektoru, kombinace se záporným indexem:

   0 2 _1 { 5 6 7 8
5 7 8

Výběr více prvků z vektoru, kombinace se záporným indexem:

   0 2 _2 { 5 6 7 8
5 7 7

A konečně výběry prvků z matice:

Konstrukce matice:

   3 3 $ i. 9
0 1 2
3 4 5
6 7 8

Výběr celého řádku z matice:

   1 { 3 3 $ i. 9
3 4 5

Záporný index při výběru:

   _1 { 3 3 $ i. 9
6 7 8

Výběr řádků v opačném pořadí z matice:

   2 1 0 { 3 3 $ i. 9
6 7 8
3 4 5
0 1 2

Zopakování vybraných řádků:

   2 1 2 1 2 1 { 3 3 $ i. 9
6 7 8
3 4 5
6 7 8
3 4 5
6 7 8
3 4 5

Výběr konkrétního prvku z matice:

   (< 1 ; 1) { 3 3 $ i. 9
4

Výběr podmatice:

   (< 1 2 ; 1 2) { 3 3 $ i. 9
4 5
7 8

Výběr podmatice:

   (< 0 1 ; 0 1) { 3 3 $ i. 9
0 1
3 4

Výběr sloupce z matice:

   (< 0 1 2; 1) { 3 3 $ i. 9
1 4 7

15. Predikáty pracující s atomy, vektory i maticemi

Pro vzájemné porovnávání skalárních hodnot i hodnot prvků uložených ve vektorech, maticích i polích s vyššími dimenzemi se používají predikátové funkce nahrazující relační operátory známé z jiných programovacích jazyků (slovo operátor má v jazyce J odlišný význam). Návratovou hodnotou těchto funkcí je buď skalární hodnota 0 nebo 1, popř. vektor či matice obsahující pouze nuly a jedničky (nula samozřejmě značí nepravdu, jednička pravdu). Tyto funkce jsou popsány v následující tabulce. Povšimněte si především způsobu zápisu podmínky „menší nebo rovno“, „větší nebo rovno“ a „nerovnost“, protože se v nich používají znaky, které jsou oproti jiným programovacím jazykům odlišné (jenže co není v jazyce J odlišné, že?):

Symbol funkce Forma funkce Popis (význam)
< dyadická predikát „menší než“
<: dyadická predikát „menší nebo rovno“
> dyadická predikát „větší než“
>: dyadická predikát „větší nebo rovno“
= dyadická predikát rovnosti
~: dyadická predikát nerovnosti
e. dyadická predikát „obsahuje“

Použití výše uvedených funkcí při porovnávání skalárních hodnot je velmi snadné, o čemž se můžeme velmi snadno přesvědčit:

   1 <: 2
1
 
   1 >: 2
0
 
   1 <: 1
1
 
   1 ~: 2
1
 
   1 ~: 1
0

Kromě vzájemného porovnání skalárních hodnot je možné porovnat všechny prvky vektoru (matice) se skalární hodnotou, popř. prvky dvou vektorů (matic) navzájem. V tomto případě je výsledkem porovnání též vektor či matice obsahující hodnoty 0 a 1 (tedy vlastně bitová maska):

   NB. Porovnání všech prvků vektoru se skalární hodnotou
   1 2 3 4 > 2
0 0 1 1
 
   1 2 3 4 < 2
1 0 0 0
 
   1 2 3 4 = 2
0 1 0 0
 
   NB. Porovnání dvou vektorů, které v tomto
   NB. případě musí mít shodnou délku.
   1 2 3 4 < 4 3 2 1
1 1 0 0

Poslední funkcí, kterou si v této kapitole popíšeme, je funkce testující existenci prvku (prvků) ve vektoru či matici. Jedná se o funkci označovanou symbolem e., jejímž prvním parametrem je skalární hodnota či vektor hodnot, které se hledají v datové struktuře předané ve druhém parametru této funkce. Návratovou hodnotou funkce e. je pravdivostní hodnota 0 nebo 1 udávající, zda se příslušná hledaná hodnota (první parametr) skutečně ve druhém parametru nachází. Pokud se současně vyhledává více hodnot, je návratovou hodnotou vektor nul a jedniček (tedy opět bitové pole), jak je to ostatně ukázáno v následujících demonstračních příkladech:

   NB. Vytvoření vektoru čísel
   x=:1 2 3 4 5 0.3 _1 42
 
   NB. Zjištění, zda vektor obsahuje hodnotu 10
   10 e. x
0
 
   NB. Zjištění, zda vektor obsahuje hodnotu 1
   1 e. x
1
 
   NB. Dtto pro hodnotu 2
   2 e. x
1
 
   NB. Vytvoření vektoru hledaných čísel
   y=:1 3 5
 
   NB. Zjištění, zda vektor x obsahuje čísla 1, 3 a 5
   y e. x
1 1 1
 
   NB. Vyhledání více prvků bez použití
   NB. pomocného vektoru
   1 10 100 1000 42 e. x
1 0 0 0 1
 
   NB. Vektor, ve kterém je prováděno vyhledávání,
   NB. může být sestrojen funkcí i.
   1 5 10 e. i. 10
1 1 0
 
   NB. Vyhledání všech násobků dvou v řadě
   NB. obsahující násobky čísla 3.
   (2* i. 20) e. (3* i. 20)
1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0 0 1 0
Poznámka: v posledním příkladu je již vidět základ pro výpočet prvočísel:
   I.2=+/0=|/~ i.100
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

16. Různé způsoby spojení polí

V jazyku J existuje hned několik různých operací pro spojení dvou polí:

Symbol funkce Forma funkce Jméno
, dyadická append
,. dyadická stitch
,: dyadická laminate
; dyadická link

Tyto funkce budou ukázány na několika příkladech:

Spojení vektorů funkcí append:

   1 2 3 , 4 5 6
1 2 3 4 5 6

Spojení matic funkcí append („pod sebe“):

   (2 3 $ i. 6) , 2 3 $ i. 6
0 1 2
3 4 5
0 1 2
3 4 5

Matice nemusí mít stejný počet řádků:

   (2 3 $ i. 6) , 3 3 $ i. 9
0 1 2
3 4 5
0 1 2
3 4 5
6 7 8

Připojení skaláru k vektoru s možným opakováním skalární hodnoty:

   (i. 6) , 100
0 1 2 3 4 5 100

Připojení skaláru k matici s možným opakováním skalární hodnoty:

   (2 3 $ i. 6) , 100
  0   1   2
  3   4   5
100 100 100

Odlišný tvar původní matice:

   (3 2 $ i. 6) , 100
  0   1
  2   3
  4   5
100 100

Zopakujme si použití funkce append pro dvě matice:

   (2 3 $ i. 6) , 2 3 $ i. 6
0 1 2
3 4 5
0 1 2
3 4 5

Rozdílné chování funkce stitching pro dvě matice (spojení „za sebou“):

   (2 3 $ i. 6) ,. 2 3 $ i. 6
0 1 2 0 1 2
3 4 5 3 4 5

Funkce stitching a kombinace matice a skalární hodnoty:

   (2 3 $ i. 6) ,. 100
0 1 2 100
3 4 5 100

Funkce stitching a kombinace matice a skalární hodnoty:

   (3 2 $ i. 6) ,. 100
0 1 100
2 3 100
4 5 100

Funkce laminating spojuje dvě matice ještě jiným způsobem – jako dva boxy:

   (2 3 $ i. 6) ,: 2 3 $ i. 6
0 1 2
3 4 5
 
0 1 2
3 4 5

Výsledkem je vždy pole obsahující „kompatibilní“ prvky

   (2 3 $ i. 6) ,: 3 2 $ i. 6
0 1 2
3 4 5
0 0 0
 
0 1 0
2 3 0
4 5 0

Další příklad kombinující matici a skalár – výsledkem je matice s dvojicí „kompatibilních“ prvků:

   (2 3 $ i. 6) ,: 100
  0   1   2
  3   4   5
 
100 100 100
100 100 100

17. Pokročilejší operace nad poli

Popišme si ještě další operace, které lze s poli provádět:

Symbol funkce Forma funkce Jméno
; dyadická linking
; monadická razing
, monadická ravelling
,. monadická itemizing

Funkce linking slouží ke konstrukci seznamu boxů obsahujících jakékoli prvky:

   (2 3 $ i. 6) ; 100
+-----+---+
|0 1 2|100|
|3 4 5|   |
+-----+---+
 
   (2 3 $ i. 6) ; 100 ; 'abcd'
+-----+---+----+
|0 1 2|100|abcd|
|3 4 5|   |    |
+-----+---+----+
 
   (2 3 $ i. 6) ; 100 ; 'abcd' ; (4 2 $ i. 8)
+-----+---+----+---+
|0 1 2|100|abcd|0 1|
|3 4 5|   |    |2 3|
|     |   |    |4 5|
|     |   |    |6 7|
+-----+---+----+---+

Monadická funkce razing naopak rozdělí pole boxů na seznam prvků:

   2 2 $ 1;2;3;4
+-+-+
|1|2|
+-+-+
|3|4|
+-+-+
 
   ; 2 2 $ 1;2;3;4
1 2 3 4

Naproti tomu monadická funkce ravelling rozdělí pole boxů na seznam boxů:

   , 2 2 $ 1;2;3;4
+-+-+-+-+
|1|2|3|4|
+-+-+-+-+

A konečně funkce itemizing zvyšuje dimenzi pole o jedničku – zabalí prvky původního pole:

   2 2 $ 1;2;3;4
+-+-+
|1|2|
+-+-+
|3|4|
+-+-+
 
   ,. 2 2 $ 1;2;3;4
+-+-+
|1|2|
+-+-+
|3|4|
+-+-+
 
   $ 2 2 $ 1;2;3;4
2 2
 
   $ ,: 2 2 $ 1;2;3;4
1 2 2

18. Operátor / (reduce)

Programovací jazyk J 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. 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. Jedním z nejdůležitějších operátorů jazyka J je operátor /, který jsme si již v jednodušší podobě představili při popisu jazyka APL. Tento operátor, který se zapisuje za 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):

   NB. Součet všech čísel v řadě od 1 do 10.
   + / 1 2 3 4 5 6 7 8 9 10
55
 
   NB. Vektor hodnot můžeme vytvořit
   NB. taktéž s využitím generátoru
   NB. indexů (viz předchozí části
   NB. seriálu). Ovšem pozor - indexy
   NB. se generují od 0, nikoli od 1.
   + / i. 10
45
 
   NB. Zde se již vektor skutečně vygeneruje
   NB. tak, že jeho první prvek má
   NB. jedničkovou hodnotu.
   + / 1 + i. 10
55

Operátor / je však samozřejmě možné použít i v kombinaci s libovolnou dyadickou funkcí – může se jednat jak o aritmetické funkce, tak i o funkce logické (booleovské), porovnávací (relační), maticové aj. Následují příklady použití některých těchto funkcí; nejprve funkcí booleovských aplikovaných na vektory binárních hodnot:

   NB. Použití booleovské funkce "or"
   NB. (logický součet)
   +./ 0 0 0 0
0
 
   +./ 0 0 0 1
1
 
   +./ 1 1 1 1
1
 
   NB. Použití booleovské funkce "and"
   NB. (logický součin)
   *./ 0 0 0 0
0
 
   *./ 0 0 0 1
0
 
   *./ 1 1 1 1
1
 
   NB. Použití booleovské funkce ekvivalence
   =/ 0 0 0 0
1
 
   =/ 0 0 0 1
0
 
   =/ 1 1 1 1
1
 
   NB. Použití booleovské funkce "xor"
   NB. (nonekvivalence)
   ~:/ 0 0 0 0
0
 
   ~:/ 0 0 0 1
1
 
   ~:/ 1 1 1 1
0

Mezi další dyadické funkce, které lze zkombinovat s operátorem /, patří například funkce pro výpočet (zjištění) minima, maxima, součinu (zde korespondujících prvků vektorů) a mocniny o zvoleném základu:

   NB. Výběr nejmenšího prvku z vektoru.
   <. / 5 4 67 2 1 42 3 7 6
1
 
   NB. Výběr největšího prvku z vektoru.
   >. / 5 4 67 2 1 42 3 7 6
67
 
   NB. Jeden ze způsobů výpočtu skalárního
   NB. součinu dvou vektorů.
   +/ (1 2 3) * (1 2 3)
14
 
   NB. Skalární součin dvou na sebe kolmých
   NB. vektorů je vždy nulový.
   +/ (1 0 0) * (0 1 0)
0
 
   NB. Výpočet prvních deseti mocnin
   NB. základu 2 (včetně 2^0).
   2 ^ i. 10
1 2 4 8 16 32 64 128 256 512
 
   NB. Suma prvních deseti mocnin
   NB. základu 2. Výsledek by měl
   NB. být roven: (2^(n+1))-1
   + / 2 ^ i. 10
1023
 
   NB. Výpočet známé úlohy se šachovnicí a semínky
   NB. kladenými na jednotlivá políčka šachovnice.
   2 ^ i. 64
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192
16384 32768 65536 131072 262144 524288 1.04858e6
2.09715e6 4.1943e6 8.38861e6 1.67772e7 3.35544e7
6.71089e7 1.34218e8 2.68435e8 5.36871e8 1.07374e9
2.14748e9 4.29497e9 8.58993e9 1.71799e10 3.43597e10 6.87195...
 
   NB. Celkový počet všech semínek na šachovnici.
   + / 2 ^ i. 64
1.84467e19

Nyní si ukážeme příklad převzatý z elektronické knihy „J for C Programmers“, ve kterém je předvedeno, jakým způsobem je možné pomocí operátoru / nalézt největší prvek v matici (zmíněná elektronická kniha je obsažena přímo v instalaci vývojového prostředí programovacího jazyka J). Nejprve si uveďme odpovídající céčkový program, který nalezne prvek s maximální hodnotou v (dvourozměrné) matici x, jejíž rozměry jsou uloženy v konstantách xsize0 a xsize1:

int i, j;
float maxval = x[0][0];
for (i = 0; i&jt;=xsize0; ++i)
{
    for (j = 0; j<=xsize1; ++j)
    {
        if (x[i][j] > maxval)
        {
            maxval = x[i][j];
        }
    }
}

V programovacím jazyku J lze maximální prvek v matici nalézt dvojí aplikací operátoru / zkombinovaného s funkcí >. (ta provádí výběr větší hodnoty z dvojice předaných parametrů, tj. jak skalárních hodnot, tak i vektorů popř. matic). První aplikace operátoru / slouží k výběru těch prvků na jednotlivých řádcích matice, které mají největší hodnotu, druhá aplikace pak již z tohoto mezivýsledku (tj. vektoru) vybere přímo maximální hodnotu, takže se celá sekvence zanořených smyček a podmíněného příkazu v programovacím jazyku J zmenší na jediný výraz. Ve skutečnosti je však možné podmíněný příkaz eliminovat i v céčkovém programu, stačí ho nahradit například voláním makra MAX, což však již není možné v příkladu uvedeném níže. Navíc si nikde nemusíme pamatovat rozměry pole (matice), neboť ty lze kdykoli za běhu programu zjistit:

   NB. Nejprve si vytvoříme matici
   NB. s testovacími daty.
   matice =: 3 3 $ _4 + i.9
   matice
_4 _3 _2
_1  0  1
 2  3  4
 
   NB. Nalezneme největší prvek v matici
   NB. dvojím použitím operátoru /
   (<./) <./ matice
4

Druhý demonstrační příklad je již poněkud složitější – nalezení sloupce, ve kterém se nachází prvek s maximální hodnotou –, ale při použití programovacího jazyka J se opět obejdeme bez nutnosti použití programových smyček a podmínek. Sloupec, ve kterém se prvek s největší hodnotou v matici nachází, lze zjistit s využitím dyadické funkce i. (index of), která vrací index prvního prvku obsahujícího danou hodnotu (prvním parametrem této funkce je většinou vektor, druhým parametrem hledaná hodnota). Povšimněte si především použití závorek, které eliminují nutnost dvojího použití mezivýsledku >./ matice v zapisovaném výrazu:

(i. >./) >./ matice

Céčkovský ekvivalent je stále mnohonásobně delší kvůli nutnosti použití programových smyček a podmínek:

int i, j, maxcol = 0;
float maxval = x[0][0];
for (i = 0; i&jt;=xsize0; ++i)
{
    for (j = 0; j<=xsize1; ++j)
    {
        if (x[i][j] > maxval)
        {
            maxval = x[i][j];
            maxcol = j
        }
    }
}

19. Dyadická forma operátoru /

Při popisu programovacího jazyka APL jsme se mj. zmínili i o operátoru „outer product“ zapisovaného dvojicí symbolů ◦. (kolečko+tečka) za nimiž následovalo jméno či symbol nějaké primitivní funkce popř. identifikátor uživatelské 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 této operace je matice Z obsahující v prvku zij návratovou hodnotu funkce aplikované na prvky xi a yj. Význam tohoto operátoru jsme si vysvětlili na příkladu, ve kterém se vytvořila a následně vypsala část tabulky malé násobilky (pozor – následující úryvek kódu je zapsaný v syntaxi odpovídající programovacímu jazyku APL, nikoli J):

     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

Podobně jsme v APL postupovali při výpočtu prvočísel:

(~R∊R∘.×R)/R←1↓⍳x

Programovací jazyk J sice neobsahuje specializovaný operátor typu ◦., ale ani to vlastně není zapotřebí, protože rozšiřuje možnosti operátoru / popsaného v předchozí kapitole. Zatímco v APL byl operátor / (reduce) pouze monadický (což znamená, že ho bylo možné použít s parametrem zapisovaným napravo od identifikátoru funkce), je možné v programovacím jazyce J využít i jeho dyadickou formu, při níž se první parametr (vektor) zapisuje nalevo od operátoru+funkce a druhý parametr (většinou taktéž vektor) napravo. Výsledek aplikace „dyadického“ operátoru / (nazývaného poněkud neobvykle table) je v tomto případě stejný, jako při použití operátoru ◦. v programovacím jazyce APL (u některých funkcí použitých spolu s tímto operátorem dochází k několika malým změnám chování, které však nejsou v naprosté většině případů podstatné).

Výše uvedený příklad by se tedy dal přepsat do programovacího jazyka J dvěma způsoby: přímým zápisem dvojic vektorů, na něž by se aplikoval operátor „/“ v kombinaci s funkcí násobení, nebo využitím generátoru indexů pro zkonstruování obou vektorů. Ve druhém případě opět nesmíme zapomenout na to, že se indexy generují od nuly a nikoli od jedničky:

   NB. Tabulka malé násobilky vzniklá
   NB. aplikací operátoru "outer product"
   NB. na dvojici explicitně zapsaných vektorů
   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
 
   NB. Použití generátoru indexů pro výpočet
   NB. tabulky malé násobilky.
   (1+i.5) */ (1+i.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

Použít lze – i když nepříliš idiomaticky – funkci drop:

   (}. i.6) */ (}. i.6)
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

Popř. bez nadbytečných mezer a závorek:

   (}.i.6)*/}.i.6
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

S využitím operátoru outer product 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:

skoleni

   NB. Pomocný vektor obsahující číselnou
   NB. řadu 0 1 2 3 4 5
   vect =. i. 5
 
   NB. Matice obsahující prvky se shodnými
   NB. hodnotami na vedlejších diagonálách.
   vect +/ vect
0 1 2 3 4
1 2 3 4 5
2 3 4 5 6
3 4 5 6 7
4 5 6 7 8
 
   NB. Jednotková matice.
   vect =/ vect
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
 
   NB. Inverze všech prvků jednotkové
   NB. matice.
   vect ~:/ vect
0 1 1 1 1
1 0 1 1 1
1 1 0 1 1
1 1 1 0 1
1 1 1 1 0
 
   NB. Rotace jednotkové matice
   |. vect =/ vect
0 0 0 0 1
0 0 0 1 0
0 0 1 0 0
0 1 0 0 0
1 0 0 0 0
 
   NB. Matice obsahující NAD hlavní
   NB. diagonálou jednotkové prvky.
   vect </ vect
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
 
   NB. Matice obsahující NAD hlavní
   NB. diagonálou (včetně diagonály)
   NB. jednotkové prvky.
   vect </ vect
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
 
   NB. Matice obsahující POD hlavní
   NB. diagonálou (včetně diagonály)
   NB. jednotkové prvky.
   vect >:/ vect
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
 
   NB. Na hlavní diagonále je
   NB. číselná posloupnost začínající
   NB. nulou, ostatní prvky jsou nulové
   vect * vect =/ vect
0 0 0 0 0
0 1 0 0 0
0 0 2 0 0
0 0 0 3 0
0 0 0 0 4
 
   NB. Na hlavní diagonále je
   NB. číselná posloupnost začínající
   NB. jedničkou, ostatní prvky jsou nulové
   (vect+1) * vect =/ vect
1 0 0 0 0
0 2 0 0 0
0 0 3 0 0
0 0 0 4 0
0 0 0 0 5
 
   NB. Rotace předchozí matice
   |. (vect+1) * vect =/ vect
0 0 0 0 5
0 0 0 4 0
0 0 3 0 0
0 2 0 0 0
1 0 0 0 0

Příklad použití operátoru / s nekomutativní funkcí:

   (i.5) ^/ (i.5)
   1 0  0  0   0
   1 1  1  1   1
   1 2  4  8  16
   1 3  9 27  81
   1 4 16 64 256

Kdo dává přednost transponované tabulce (mocniny rostou po jednotlivých řádcích, základ po sloupcích), může použít funkci |: aplikovanou na vypočtenou matici. I v tomto případě totiž platí, že jsou funkce vyčíslovány zprava doleva, nejdříve je tedy vypočtena matice 5×5 hodnot, která je až následně transponována:

   |: (i.5) ^/ (i.5)
   1 1  1  1   1
   0 1  2  3   4
   0 1  4  9  16
   0 1  8 27  64
   0 1 16 81 256
 
   NB. Kratší zápis pro ty, co šetří
   NB. každý stisk klávesy :-)
   |:(i.5)^/i.5
   1 1  1  1   1
   0 1  2  3   4
   0 1  4  9  16
   0 1  8 27  64
   0 1 16 81 256

20. Odkazy na Internetu

  1. 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/
  2. Programovací technika nazvaná tacit programming
    https://www.root.cz/clanky/pro­gramovaci-technika-nazvana-tacit-programming/
  3. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/
  4. NuVoc
    https://code.jsoftware.com/wiki/NuVoc
  5. J (programming language) [Wikipedia]
    https://en.wikipedia.org/wi­ki/J_%28programming_langu­age%29
  6. J – Absolutely Essential Terms
    https://code.jsoftware.com/wi­ki/Vocabulary/AET
  7. J – Atoms and Arrays
    https://code.jsoftware.com/wi­ki/Vocabulary/Nouns#Atom
  8. Why J
    https://www.jsoftware.com/hel­p/primer/why_j.htm
  9. What is an Array?
    https://vector.org.uk/what-is-an-array/
  10. Comments
    http://www.gavilan.edu/csis/lan­guages/comments.html
  11. Vector (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Vector.html
  12. n-Tuple (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Tuple.html
  13. n-Vector (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Vector.html
  14. Matrix (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Matrix.html
  15. Array (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Array.html
  16. ND Arrays (Tensors) in different languages
    https://www.youtube.com/wat­ch?v=WbpbEilgQBc
  17. Extending APL to Infinity\
    https://www.jsoftware.com/pa­pers/eem/infinity.htm
  18. Vector Library (R7RS-compatible)
    https://srfi.schemers.org/srfi-133/srfi-133.html
  19. Vectors (pro Gauche)
    https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html
  20. Kawa: Compiling Scheme to Java
    https://www.mit.edu/afs.new/sip­b/project/kawa/doc/kawa-tour.html
  21. Kawa in Languages shootout
    http://per.bothner.com/blog/2010/Kawa-in-shootout/
  22. Kawa 2.0 Supports Scheme R7RS
    https://developers.slashdot­.org/story/14/12/13/2259225/ka­wa-20-supports-scheme-r7rs/
  23. Kawa — fast scripting on the Java platform
    https://lwn.net/Articles/623349/
  24. Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
    http://incanter.org/
  25. Evolution of incanter (Gource Visualization)
    https://www.youtube.com/wat­ch?v=TVfL5nPELr4
  26. Questions tagged [incanter] (na Stack Overflow)
    https://stackoverflow.com/qu­estions/tagged/incanter?sor­t=active
  27. Data Sorcery with Clojure
    https://data-sorcery.org/contents/
  28. Back to the Future: Lisp as a Base for a Statistical Computing System
    https://rd.springer.com/chap­ter/10.1007/978–3–7908–2084–3_2
  29. Incanter Cheat Sheet
    http://incanter.org/docs/incanter-cheat-sheet.pdf
  30. Back to the Future: Lisp as a Base for a Statistical Computing System (celá verze článku)
    https://www.researchgate.net/pu­blication/227019917_Back_to_the_Fu­ture_Lisp_as_a_Base_for_a_Sta­tistical_Computing_System
  31. BQN: finally, an APL for your flying saucer
    https://mlochbaum.github.io/BQN/
  32. Is BQN stable?
    https://mlochbaum.github.i­o/BQN/commentary/stability­.html
  33. Specification: BQN system-provided values
    https://mlochbaum.github.i­o/BQN/spec/system.html
  34. Tutorial: BQN expressions
    https://mlochbaum.github.i­o/BQN/tutorial/expression­.html
  35. BQN primitives
    https://mlochbaum.github.i­o/BQN/doc/primitive.html
  36. Function trains
    https://mlochbaum.github.i­o/BQN/doc/train.html
  37. BQN community links
    https://mlochbaum.github.i­o/BQN/community/index.html
  38. BQN UV
    https://observablehq.com/@lsh/bqn-uv
  39. APL Wiki
    https://aplwiki.com/wiki/
  40. The Array Cast
    https://www.arraycast.com/e­pisodes/episode-03-what-is-an-array
  41. EnthusiastiCon 2019 – An Introduction to APL
    https://www.youtube.com/wat­ch?v=UltnvW83_CQ
  42. Dyalog
    https://www.dyalog.com/
  43. Try APL!
    https://tryapl.org/
  44. Lisp-Stat Information
    http://homepage.cs.uiowa.e­du/~luke/xls/xlsinfo/
  45. Sample Plots in Incanter
    https://github.com/incanter/in­canter/wiki/Sample-Plots-in-Incanter#line
  46. vectorz-clj
    https://github.com/mikera/vectorz-clj
  47. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  48. 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
  49. Vectors and matrices in Julia
    https://fncbook.github.io/v1­.0/linsys/demos/matrices-julia.html
  50. Array vs Matrix in R Programming
    https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/
  51. Concurrency (computer science)
    https://en.wikipedia.org/wi­ki/Category:Concurrency_%28com­puter_science%29
  52. Koprogram
    https://cs.wikipedia.org/wi­ki/Koprogram
  53. Coroutine
    https://en.wikipedia.org/wi­ki/Coroutine
  54. Coroutines in C
    http://www.chiark.greenen­d.org.uk/~sgtatham/corouti­nes.html
  55. S-expression (Wikipedia)
    https://en.wikipedia.org/wiki/S-expression
  56. S-Expressions (Rosetta Code)
    http://rosettacode.org/wiki/S-Expressions
  57. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  58. Tutorial for the Common Lisp Loop Macro
    http://www.ai.sri.com/pkarp/loop.html
  59. 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
  60. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  61. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  62. Clojure Macros and Metaprogramming
    http://clojure-doc.org/articles/language/macros.html
  63. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  64. CS 2101 Parallel Computing with Julia
    https://www.coursehero.com/fi­le/11508091/CS-2101-Parallel-Computing-with-Julia/
  65. Julia By Example
    https://samuelcolvin.github­.io/JuliaByExample/
  66. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  67. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  68. no stinking loops – Kalothi
    http://www.nsl.com/
  69. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  70. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  71. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  72. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  73. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  74. A+
    http://www.aplusdev.org/
  75. APLX
    http://www.microapl.co.uk/
  76. FreeAPL
    http://www.pyr.fi/apl/index.htm
  77. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  78. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  79. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  80. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  81. Parrot APL (GPL)
    http://www.parrotcode.org/
  82. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  83. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  84. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  85. Introducing Julia/Functions
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Functi­ons
  86. Functions (Julia documentation)
    https://docs.julialang.or­g/en/v1/manual/functions/
  87. Evaluate binomial coefficients
    http://rosettacode.org/wi­ki/Evaluate_binomial_coef­ficients
  88. Ackermann function
    http://rosettacode.org/wi­ki/Ackermann_function
  89. Julia (front page)
    http://julialang.org/
  90. Julia – dokumentace
    http://docs.julialang.org/
  91. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  92. Julia (programming language)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  93. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  94. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  95. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  96. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  97. Learn X in Y minutes (where X=Julia)
    https://learnxinyminutes.com/doc­s/julia/
  98. New Julia language seeks to be the C for scientists
    http://www.infoworld.com/ar­ticle/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html
  99. Julia: A Fast Dynamic Language for Technical Computing
    http://karpinski.org/publi­cations/2012/julia-a-fast-dynamic-language
  100. The LLVM Compiler Infrastructure
    http://llvm.org/
  101. Julia: benchmarks
    http://julialang.org/benchmarks/
  102. Type system
    https://en.wikipedia.org/wi­ki/Type_system
  103. Half-precision floating-point format
    https://en.wikipedia.org/wiki/Half-precision_floating-point_format
  104. Dartmouth BASIC
    https://en.wikipedia.org/wi­ki/Dartmouth_BASIC
  105. BASIC 4th Edition
    http://www.bitsavers.org/pdf/dar­tmouth/BASIC_4th_Edition_Jan68­.pdf
  106. VECTRAN
    https://encyclopedia2.the­freedictionary.com/VECTRAN
  107. Comparison of programming languages (array)
    https://en.wikipedia.org/wi­ki/Comparison_of_programmin­g_languages_(array)
  108. BASIC at 50
    https://www.dartmouth.edu/ba­sicfifty/commands.html
  109. BBC Basic – arrays
    http://www.riscos.com/sup­port/developers/bbcbasic/par­t2/arrays.html
  110. Datová struktura
    https://cs.wikipedia.org/wi­ki/Datov%C3%A1_struktura
  111. SIMD instrukce využívané v moderních mikroprocesorech řady x86
    https://www.root.cz/clanky/simd-instrukce-vyuzivane-v-modernich-mikroprocesorech-rady-x86/
  112. 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/
  113. 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/

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.