Nial Array Language: další z jazyků inspirovaných APL

4. 10. 2022
Doba čtení: 40 minut

Sdílet

Autor: Nash Gordon, Wikimedia, podle licence: CC BY-SA 4.0
V pořadí již desátém článku věnovaném jazykům z oblasti „array programmingu“ se budeme věnovat jazyku, který se jmenuje Nial neboli Nested Interactive Array Language. Opět se přitom jedná o jazyk z rodiny odvozené od APL.

Obsah

1. Nial Array Language: další z jazyků inspirovaných APL

2. Základní vlastnosti programovacího jazyka Nial

3. Stručné porovnání s dalšími jazyky z rodiny APL

4. Překlad a první spuštění interpretru jazyka Nial

5. Pole ve funkci základního datového typu programovacího jazyka Nial

6. Modifikace prvků pole a další základní operace s poli

7. Počet dimenzí a tvar pole

8. Změna tvaru pole funkcí reshape

9. Funkce umožňující konstrukce polí

10. Funkce pro vygenerování polí

11. Pole a relační operátory

12. Funkce operující s celým polem

13. Pole jakožto rekurzivní datová struktura

14. Zobecněný outer product

15. Zobecněný skalární součin (inner product)

16. Další ukázky práce s poli

17. Definice funkcí

18. Závěrečné zhodnocení

19. Předchozí články o rozsáhlém světu „array programmingu“

20. Odkazy na Internetu

1. Nial Array Language: další z jazyků inspirovaných APL

V pořadí již desátém článku věnovaném programovacím jazykům z oblasti „array programmingu“ (viz též odkazy uvedené v devatenácté kapitole) se budeme věnovat programovacímu jazyku, který se jmenuje Nial neboli Nested Interactive Array Language. Tento programovací jazyk patří do rodiny jazyků, které jsou odvozeny od APL, jehož autorem je, jak již víme, Ken Iverson. Do této rodiny patří kromě samotného jazyka APL i jazyky J, K, Q a v neposlední řadě i relativní novinka – jazyk BQN (ovšem patří sem i „kalkulačka“ Ivy). Naproti tomu se v případě programovacího jazyka Nial, kterému se budeme věnovat dnes, o žádnou žhavou novinku nejedná, protože tento programovací jazyk začal vznikat již na začátku osmdesátých let minulého století. I přesto však v něm nalezneme některé zajímavé koncepty, díky nimž se Nial odlišuje od všech výše uvedených jazyků a tedy má smysl se jím zabývat.

Poznámka: některé „historické novinky“, které byly přidány do Nialu v průběhu předchozích čtyřiceti let, se objevily například v NumPy a Julii (viz další text).

2. Základní vlastnosti programovacího jazyka Nial

Jak jsme si již naznačili v úvodní kapitole, je Nial programovacím jazykem pocházejícím z rodiny APL. Do samotného jazyka však byly přidány některé funkcionální prvky, podobně, jako tomu je například v jazyku K či BQN. Základním a ústředním datovým typem je zde (což asi není velké překvapení) n-dimenzionální pole (array), které dokonce při provádění výpočtů nahrazuje i skalární hodnoty. To například znamená, že i znaky, pravdivostní hodnoty nebo celá čísla jsou při provádění různých operací chápána jako pole s jediným prvkem, ovšem jejich typ je odlišný, protože se jedná o takzvané atomy. A logicky je tomu i naopak – pole mohou jako své prvky obsahovat jiná pole, tj. jedná se o rekurzivní datovou strukturu (tento koncept chápání polí ovšem nenajdeme ve všech jazycích odvozených od APL, například ji nemá jazyk J).

Ovšem stejně jako v APL se i v Nialu pracuje s funkcemi jako s operátory, tj. operandy/parametry se mohou zapsat okolo jména funkce (což vyžaduje, aby funkce byly monadické nebo dyadické). Uveďme si jednoduchý příklad:

     1 + 2
3

Výše uvedený zápis znamená volání funkce nazvané + alias sum, které se předávají dva parametry – každý z parametrů je přitom chápán jako pole s jediným prvkem, tj. první pole obsahuje prvek s hodnotou 1 a druhé pole obsahuje prvek s hodnotou 2. Hodnota 3 vypsaná na dalším řádku je výsledek celé operace. Opět se z pohledu dalšího zpracování nemusí jednat jen o skalární hodnotu 3, ale o pole s jediným prvkem rovným trojce.

Alternativně lze ovšem funkci volat i tak, že se její jméno uvede na začátku výrazu, za nímž následují parametry funkce:

     + 1 2
3

Takto volaná funkce akceptuje i větší množství parametrů:

     + 1 2 3
6

Namísto symbolu + ovšem můžeme použít i plné jméno funkce sum a přepsat všechny tři předchozí výrazy následovně:

     1 sum 2
3
 
     sum 1 2
3
 
     sum 1 2 3
6

Sčítat je ovšem možné i dvě pole, resp. v tomto případě dvojici dvouprvkových vektorů:

     1 2 + 2 3
3 5

Podporováno je i přičtení (zdánlivé) skalární hodnoty s polem:

     1 + 2 3 4
3 4 5

     1 2 3 + 4
5 6 7

Pozor si musíme dát především na to, že se nerozlišují priority aritmetických operací (protože se vlastně jedná o volání funkcí) a operace se vyhodnocují zleva doprava, na rozdíl od většiny ostatních jazyků z rodiny APL. V případě potřeby se tedy musíme pomoci závorkami:

     1 + 2 * 3
9
     1 + (2 * 3)
7
     (1 + 2) * 3
9
Poznámka: to jsou ovšem jen naprosté základy jazyka Nial. Více příkladů si ukážeme ve chvíli, kdy budeme mít nainstalovánu interaktivní smyčku REPL tohoto jazyka.

3. Stručné porovnání s dalšími jazyky z rodiny APL

Jazyk Nial sice vychází z konceptů, které byly zavedeny v rámci programovacího jazyka APL, ovšem v některých ohledech se od těchto jazyků odlišuje. Především je zde patrná snaha o pojmenování funkcí a operátorů takovým způsobem, aby byl výsledek čitelný. To je poměrně velký posun od filozofie APL, J i K (Q), kde je čitelnost nahrazena za krátký zápis výpočtů či celých algoritmů (což značí, že se jedná o odlišný způsob nasazení těchto jazyků – APL evidentně sází na rozpoznávání vzorů, které se tak postupně stanou součástí „slovníku“ programátora). To je ovšem především syntaktický rozdíl, který nemusí být až tak zásadní. Důležitější jsou další rozdíly, z nichž některé jsou zmíněny na stránce https://github.com/codereport/array-language-comparisons.

Zajímavé je, že funkce (monadické i dyadické) se vyhodnocují zleva doprava, zatímco u dalších APL jazyků je to zprava doleva. Prvky pole jsou indexovány od nuly, zatímco v APL je index prvního prvku volitelný a běžné „inženýrské“ a matematické/statistické jazyky indexují od jedničky (Fortran, Julia, Mathematica, Matlab, R, Wolfram language).

Poznámka: většinou se též porovnává, jestli jsou matice uložené „po řádcích“ nebo „po sloupcích“, ovšem v jazycích odvozených od APL je – což může být překvapivé – tento rozdíl v praxi jen minimální, protože se s maticemi nepracuje po jednotlivých prvcích v programových smyčkách.

4. Překlad a první spuštění interpretru jazyka Nial

Programovací jazyk Nial je dostupný jak ve formě binárních spustitelných souborů, tak i ve formě zdrojových kódů. Ukažme si tedy překlad Nialu. K tomu budeme potřebovat překladač programovacího jazyka C, překladač jazyka C++ (kvůli naprosto marginální části kódu), a taktéž CMake.

Nejprve naklonujeme repositář se zdrojovými kódy:

$ git clone https://github.com/niallang/Nial_Development.git
 
Cloning into 'Nial_Development'...
remote: Enumerating objects: 2024, done.
remote: Counting objects: 100% (205/205), done.
remote: Compressing objects: 100% (140/140), done.
remote: Total 2024 (delta 83), reused 144 (delta 57), pack-reused 1819
Receiving objects: 100% (2024/2024), 31.04 MiB | 36.83 MiB/s, done.
Resolving deltas: 100% (549/549), done.

Ve druhém kroku se přesuneme do naklonovaného repositáře a spustíme překlad:

$ bash ./build.sh
 
-- The C compiler identification is GNU 12.2.1
-- The CXX compiler identification is GNU 12.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/Nial_Development/BuildCore/build
[  3%] Building C object CMakeFiles/nialcore.dir/absmach.c.o
[  7%] Building C object CMakeFiles/nialcore.dir/arith.c.o
[ 10%] Building C object CMakeFiles/nialcore.dir/atops.c.o
[ 14%] Building C object CMakeFiles/nialcore.dir/basics.c.o
[ 17%] Building C object CMakeFiles/nialcore.dir/blders.c.o
[ 21%] Building C object CMakeFiles/nialcore.dir/compare.c.o
[ 25%] Building C object CMakeFiles/nialcore.dir/eval.c.o
[ 28%] Building C object CMakeFiles/nialcore.dir/insel.c.o
[ 32%] Building C object CMakeFiles/nialcore.dir/lib_main.c.o
[ 35%] Building C object CMakeFiles/nialcore.dir/linalg.c.o
[ 39%] Building C object CMakeFiles/nialcore.dir/logicops.c.o
[ 42%] Building C object CMakeFiles/nialcore.dir/main_stu.c.o
[ 46%] Building C object CMakeFiles/nialcore.dir/linenoise.c.o
[ 50%] Building C object CMakeFiles/nialcore.dir/parse.c.o
[ 53%] Building C object CMakeFiles/nialcore.dir/picture.c.o
[ 57%] Building C object CMakeFiles/nialcore.dir/profile.c.o
[ 60%] Building C object CMakeFiles/nialcore.dir/scan.c.o
[ 64%] Building C object CMakeFiles/nialcore.dir/symtab.c.o
[ 67%] Building C object CMakeFiles/nialcore.dir/systemops.c.o
[ 71%] Building C object CMakeFiles/nialcore.dir/trig.c.o
[ 75%] Building C object CMakeFiles/nialcore.dir/trs.c.o
[ 78%] Building C object CMakeFiles/nialcore.dir/unixif.c.o
[ 82%] Building C object CMakeFiles/nialcore.dir/windowsif.c.o
[ 85%] Building C object CMakeFiles/nialcore.dir/utils.c.o
[ 89%] Building C object CMakeFiles/nialcore.dir/wsmanage.c.o
[ 92%] Building C object CMakeFiles/nialcore.dir/bitops.c.o
[ 96%] Building C object CMakeFiles/nialcore.dir/fileio.c.o
[100%] Linking C executable nialcore
[100%] Built target nialcore
Completed work to generate source code for basic nial:
-- The C compiler identification is GNU 12.2.1
-- The CXX compiler identification is GNU 12.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /root/Nial_Development/BuildNial/build
[  3%] Building C object CMakeFiles/nial.dir/absmach.c.o
[  7%] Building C object CMakeFiles/nial.dir/arith.c.o
[ 10%] Building C object CMakeFiles/nial.dir/atops.c.o
[ 14%] Building C object CMakeFiles/nial.dir/basics.c.o
[ 17%] Building C object CMakeFiles/nial.dir/blders.c.o
[ 21%] Building C object CMakeFiles/nial.dir/compare.c.o
[ 25%] Building C object CMakeFiles/nial.dir/eval.c.o
[ 28%] Building C object CMakeFiles/nial.dir/insel.c.o
[ 32%] Building C object CMakeFiles/nial.dir/lib_main.c.o
[ 35%] Building C object CMakeFiles/nial.dir/linalg.c.o
[ 39%] Building C object CMakeFiles/nial.dir/logicops.c.o
[ 42%] Building C object CMakeFiles/nial.dir/main_stu.c.o
[ 46%] Building C object CMakeFiles/nial.dir/linenoise.c.o
[ 50%] Building C object CMakeFiles/nial.dir/parse.c.o
[ 53%] Building C object CMakeFiles/nial.dir/picture.c.o
[ 57%] Building C object CMakeFiles/nial.dir/profile.c.o
[ 60%] Building C object CMakeFiles/nial.dir/scan.c.o
[ 64%] Building C object CMakeFiles/nial.dir/symtab.c.o
[ 67%] Building C object CMakeFiles/nial.dir/systemops.c.o
[ 71%] Building C object CMakeFiles/nial.dir/trig.c.o
[ 75%] Building C object CMakeFiles/nial.dir/trs.c.o
[ 78%] Building C object CMakeFiles/nial.dir/unixif.c.o
[ 82%] Building C object CMakeFiles/nial.dir/windowsif.c.o
[ 85%] Building C object CMakeFiles/nial.dir/utils.c.o
[ 89%] Building C object CMakeFiles/nial.dir/wsmanage.c.o
[ 92%] Building C object CMakeFiles/nial.dir/bitops.c.o
[ 96%] Building C object CMakeFiles/nial.dir/fileio.c.o
[100%] Linking C executable nial
[100%] Built target nial

Samotné jádro jazyka Nial (bez dalších knihoven) je dostupné v podadresáři BuildCore/build:

$ cd BuildCore/build

Výsledný spustitelný soubor se jmenuje nialcore:

$ ls -l
 
total 584
-rw-r--r--. 1 tester tester  14019 Sep 29 08:46 CMakeCache.txt
drwxr-xr-x. 1 tester tester    294 Sep 29 08:46 CMakeFiles
-rw-r--r--. 1 tester tester   1644 Sep 29 08:46 cmake_install.cmake
-rw-r--r--. 1 tester tester  23109 Sep 29 08:46 Makefile
-rwxr-xr-x. 1 tester tester 549280 Sep 29 08:46 nialcore

Můžeme si otestovat jeho spuštění:

$ ./nialcore 
 
SYNTAX: nial  [(+|-)size Wssize] [-defs Filename] [-i] [-lws WSName] [-h]
 
-size Wssize
      Begin with a workspace size of Wssize words. A suffix of G, M or K
      can be used to indicate Giga words, Mega words or Kilo words respectively.
      The workspace expands if space is available.
+size Wssize
      Fix the workspace size at Wssize words with no expansion.
-defs Filename
      After loading the initial workspace the file Filename.ndf
      is loaded and executed without displaying input lines.
-lws  Wsname
      A previously saved workspace file is loaded on startup.
-i
      Execute in interactive mode with a top level loop.
-h
      Display command line syntax (this text).
 
Examples:
   nial -i
   nial -defs app.ndf
   nial +size 50M -defs newfns

Interaktivní smyčka REPL se spustí po zadání přepínače -i:

$ ./nialcore -i
 
Q'Nial V7.0 Open Source Edition Intel x86 64bit Linux Sep 29 2022
Copyright (c) NIAL Systems Limited
clear workspace created
Poznámka: Plnohodnotný interpret i se standardní knihovnou je umístěn v adresáři Nial_Development/binaries/Linux a je možné ho spustit naprosto stejným způsobem.

Nyní lze zadat nějaký výraz, který se ihned vyhodnotí:

     1+2
3

Pro opuštění REPLu nelze použít klávesovou zkratku Ctrl+D, ale příkaz „Bye“:

     Bye
Poznámka: u názvů se nerozlišují velikosti písmen, takže lze psát i:
     bye

5. Pole ve funkci základního datového typu programovacího jazyka Nial

V programovacím jazyku Nial, ostatně podobně, jako je tomu i u dalších jazyků odvozených od APL, je základním datovým typem pole (array), konkrétně obdélníkové pole, které může (rekurzivně) jako své prvky obsahovat další pole. V Nialu jsou pole obecně nehomogenním datovým typem, což znamená, že prvky jednoho pole mohou být různého typu. Obecně platí, že prvek pole je buď další pole (rekurzivní datová struktura) nebo se jedná o atom. Existuje přitom šest typů atomů: pravdivostní hodnota, celé číslo, reálné číslo, znak, řetězec a tzv. fault reprezentující nějakou formu chyby, například ?noexpr, ?eof, ?O nebo ?I.

Jednorozměrné pole se zapisuje výčtem svých prvků (jako oddělovač slouží bílé znaky):

     1 2 3
 
1 2 3

Aby bylo zřejmé, že se skutečně jedná o pole, změníme způsob jejich výpisu na terminál příkazy set:

     set "diagram
 
sketch

Tento příkaz zajistí, že se vykreslí vždy celá interní struktura pole, včetně vnořených polí.

Další volbou je:

     set "decor
 
"nodecor

Touto volbou se určuje, jakým způsobem se zobrazí znaky, řetězce a hodnoty fault tak, aby bylo zřejmé, o jaké hodnoty/struktury se jedná.

Nyní znovu zapíšeme výraz s jednorozměrným polem:

     1 2 3
 
+-+-+-+
|1|2|3|
+-+-+-+

Pole lze ovšem zkonstruovat i s využitím různých funkcí, například funkce count (což zhruba odpovídá iotě z APL):

     count 12
 
+-+-+-+-+-+-+-+-+-+--+--+--+
|1|2|3|4|5|6|7|8|9|10|11|12|
+-+-+-+-+-+-+-+-+-+--+--+--+

Poněkud speciální formou pole je prázdné pole, tj. pole bez prvků. To je reprezentováno symbolem null:

     null
 
+
|
+

6. Modifikace prvků pole a další základní operace s poli

Prvky pole je možné změnit (modifikovat, mutovat) operací nazvanou place. Tuto operaci si otestujeme na poli s deseti prvky:

     x is count 10

Změna prvního prvku pole na hodnotu 42 vypadá následovně:

     42 0 place x
42 2 3 4 5 6 7 8 9 10

Můžeme ovšem vložit do stejného prvku i kopii původního pole x, přičemž výsledkem bude složitější datová struktura:

     x 0 place x
+----------------------+-+-+-+-+-+-+-+-+--+
|+-+-+-+-+-+-+-+-+-+--+|2|3|4|5|6|7|8|9|10|
||1|2|3|4|5|6|7|8|9|10|| | | | | | | | |  |
|+-+-+-+-+-+-+-+-+-+--+| | | | | | | | |  |
+----------------------+-+-+-+-+-+-+-+-+--+

Další užitečnou operací je zjištění maximálního a minimálního prvku v poli:

     x is count 10
 
     max x
10
 
     min x
1

Tyto funkce ovšem dokážou pracovat i se dvěma poli nebo se skalárem a polem:

     5 max x
+-+-+-+-+-+-+-+-+-+--+
|5|5|5|5|5|6|7|8|9|10|
+-+-+-+-+-+-+-+-+-+--+
 
     5 min x
+-+-+-+-+-+-+-+-+-+-+
|1|2|3|4|5|5|5|5|5|5|
+-+-+-+-+-+-+-+-+-+-+

Výpočet součtu či součinu všech prvků ve vektoru nebo matici:

     x is count 10
 
     sum x
55
 
     product x
3628800

Dále můžeme aplikovat nějakou operaci na celou matici:

     x is 5 5 reshape count 25
 
     x mod 2
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1
0 1 0 1 0
1 0 1 0 1

7. Počet dimenzí a tvar pole

Interně je pole uloženo v jediném bloku paměti, ke kterému jsou přidány další metainformace. Především se jedná o počet dimenzí pole (v terminologii jazyka Nial se používá označení valence) a tvar pole neboli shape. Samotný tvar pole je reprezentován jako vektor délek rozsahů jednotlivých dimenzí pole, což například znamená, že pro matici se třemi řádky a čtyřmi sloupci bude tvar (shape) reprezentován vektorem 3, 4 (délka vektoru = počet jeho prvků, odpovídá počtu dimenzí pole.

Pole s počtem dimenzí 0 až 2 mají speciální označení a setkáme se s nimi jak v matematice, tak i v informatice:

Dimenzí Běžné označeni
0 single, atom, „jednice“?
1 seznam, vektor
2 tabulka, matice
2 a více n-rozměrné pole/matice

Počet dimenzí lze získat funkcí valence:

     valence null
1
 
     valence 42
0
 
     valence 1 2 3
1
Poznámka: hodnota 42 je atomem, tudíž má nulový počet dimenzí.

Dvourozměrné pole získáme funkcí reshape popsané dále. Zde nejdříve uložíme pole do proměnné x a následně získáme počet jeho dimenzí:

     x is 3 4 reshape 0
 
     x
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
 
     valence x
2

Podobně pro pole trojrozměrné:

     y is 2 2 2 reshape 0
 
     y
+-+-+  +-+-+
|0|0|  |0|0|
+-+-+  +-+-+
|0|0|  |0|0|
+-+-+  +-+-+
 
     valence y
3

Tvar pole (shape) se získá funkcí shape, přičemž pro atomy se bude vracet prázdné pole:

     shape null
+-+
|0|
+-+
 
     shape 42
+
|
+
 
     shape 1 2
+-+
|2|
+-+
 
     shape 1 2 3 4
+-+
|4|
+-+
 
     shape []
+-+
|0|
+-+

Dvourozměrné a trojrozměrné pole:

     x is 3 4 reshape count 12
     shape x
+-+-+
|3|4|
+-+-+
 
     x is 3 4 2 reshape count 24
     shape x
+-+-+-+
|3|4|2|
+-+-+-+
Poznámka: funkcí reshape se budeme zabývat v navazující kapitole.

Existují ještě další dvě užitečné funkce, které se dotazují na metainformace o polích. Tyto funkce se jmenují tally (počet prvků) a axes (informace o osách, resp. „indexy“ os nebo dimenzí):

     tally null
0
 
     tally 42
1
 
     tally 1 2 3
3
 
     x is 3 4 reshape 0
     tally x
12

a:

     axes null
0
 
     axes 42
(prázdná hodnota)
 
     axes 1 2 3
0
 
     axes x
0 1

8. Změna tvaru pole funkcí reshape

Další velmi důležitou funkcí, s níž se v praxi poměrně často setkáme (například i v NumPy, které z „array jazyků“ vychází), je funkce nazvaná reshape, která dokáže změnit velikost matice a vhodným způsobem přeorganizovat prvky v původní matici (celý koncept je převzat z původního APL, ostatně jak jinak). Této funkci se předávají dva parametry. Prvním parametrem je vektor s prvky určujícími tvar výsledného pole a druhým parametrem je vstupní pole (vektor, matice, …).

V následujícím příkladu je ukázáno, jak se z původního šestiprvkového vektoru vytvoří matice se třemi sloupci a dvěma řádky:

     2 3 reshape 1 2 3 4 5 6 
 
+-+-+-+
|1|2|3|
+-+-+-+
|4|5|6|
+-+-+-+
Poznámka: ve skutečnosti se prvky v operační paměti nepřesouvají – tvar pole je pouze metainformací; celý koncept se tedy značně liší například od céčkového pojetí pole.

Víme již, že funkcí count můžeme vytvořit vektor s číselnou posloupností:

     count 12
 
+-+-+-+-+-+-+-+-+-+--+--+--+
|1|2|3|4|5|6|7|8|9|10|11|12|
+-+-+-+-+-+-+-+-+-+--+--+--+

Toho můžeme využít pro tvorbu 2D matic:

     4 3 reshape count 12
 
+--+--+--+
| 1| 2| 3|
+--+--+--+
| 4| 5| 6|
+--+--+--+
| 7| 8| 9|
+--+--+--+
|10|11|12|
+--+--+--+

Trojrozměrná datová struktura, kterou si můžeme představit jako dvě matice umístěné nad sebe:

     2 3 4 reshape count 12
 
+-+--+--+--+  +-+--+--+--+
|1| 2| 3| 4|  |1| 2| 3| 4|
+-+--+--+--+  +-+--+--+--+
|5| 6| 7| 8|  |5| 6| 7| 8|
+-+--+--+--+  +-+--+--+--+
|9|10|11|12|  |9|10|11|12|
+-+--+--+--+  +-+--+--+--+

Pokud je na pravé straně reshape nedostatečný počet prvků pro vyplnění nové matice, budou prvky opakovány:

     5 5 reshape 42
 
+--+--+--+--+--+
|42|42|42|42|42|
+--+--+--+--+--+
|42|42|42|42|42|
+--+--+--+--+--+
|42|42|42|42|42|
+--+--+--+--+--+
|42|42|42|42|42|
+--+--+--+--+--+
|42|42|42|42|42|
+--+--+--+--+--+

Dtto, ovšem pro vstupní vektor s pouhými dvěma prvky:

     9 9 reshape 1 0
 
+-+-+-+-+-+-+-+-+-+
|1|0|1|0|1|0|1|0|1|
+-+-+-+-+-+-+-+-+-+
|0|1|0|1|0|1|0|1|0|
+-+-+-+-+-+-+-+-+-+
|1|0|1|0|1|0|1|0|1|
+-+-+-+-+-+-+-+-+-+
|0|1|0|1|0|1|0|1|0|
+-+-+-+-+-+-+-+-+-+
|1|0|1|0|1|0|1|0|1|
+-+-+-+-+-+-+-+-+-+
|0|1|0|1|0|1|0|1|0|
+-+-+-+-+-+-+-+-+-+
|1|0|1|0|1|0|1|0|1|
+-+-+-+-+-+-+-+-+-+
|0|1|0|1|0|1|0|1|0|
+-+-+-+-+-+-+-+-+-+
|1|0|1|0|1|0|1|0|1|
+-+-+-+-+-+-+-+-+-+

Použít lze i další datové typy, nikoli pouze celočíselné prvky:

     9 9 reshape " "X
 
+--+--+--+--+--+--+--+--+--+
|" |"X|" |"X|" |"X|" |"X|" |
+--+--+--+--+--+--+--+--+--+
|"X|" |"X|" |"X|" |"X|" |"X|
+--+--+--+--+--+--+--+--+--+
|" |"X|" |"X|" |"X|" |"X|" |
+--+--+--+--+--+--+--+--+--+
|"X|" |"X|" |"X|" |"X|" |"X|
+--+--+--+--+--+--+--+--+--+
|" |"X|" |"X|" |"X|" |"X|" |
+--+--+--+--+--+--+--+--+--+
|"X|" |"X|" |"X|" |"X|" |"X|
+--+--+--+--+--+--+--+--+--+
|" |"X|" |"X|" |"X|" |"X|" |
+--+--+--+--+--+--+--+--+--+
|"X|" |"X|" |"X|" |"X|" |"X|
+--+--+--+--+--+--+--+--+--+
|" |"X|" |"X|" |"X|" |"X|" |
+--+--+--+--+--+--+--+--+--+

9. Funkce umožňující konstrukce polí

V programovacím jazyku Nial existuje několik funkcí, které umožňují konstrukci pole, typicky ze zadaných prvků (nebo jediného prvku), popř. na základě určitého algoritmu. Základní funkce zkonstruují pole z jediného prvku, dvojice prvků, popř. ze seznamu prvků a dalšího prvku (tedy připojením dalšího prvku). Jedná se o následující funkce:

     # pole s jediným prvkem
     solitary 42
+--+
|42|
+--+

Konstrukce pole s pouhými dvěma prvky – páru:

     # pár neboli pole se dvěma prvky
     1 pair 2
+-+-+
|1|2|
+-+-+
 
     # pár, kterému se předají složitější vstupy
     1 pair 2 3 4
+-+-------+
|1|+-+-+-+|
| ||2|3|4||
| |+-+-+-+|
+-+-------+
 
     # pár, kterému se předají složitější vstupy
     1 2 3 pair 4
+-------+-+
|+-+-+-+|4|
||1|2|3|| |
|+-+-+-+| |
+-------+-+

Další funkce se jmenuje hitch. Tato funkce pracuje jinak, protože na své pravé straně (druhý operand) očekává větší množství prvků:

     1 hitch 2
+-+-+
|1|2|
+-+-+
 
     1 hitch 2 3 4
+-+-+-+-+
|1|2|3|4|
+-+-+-+-+
 
     1 2 3 hitch 4
+-------+-+
|+-+-+-+|4|
||1|2|3|| |
|+-+-+-+| |
+-------+-+

A funkce s opačným významem se jmenuje append. Tato funkce přidává prvek na konec seznamu a vrací pole:

     1 append 2
+-+-+
|1|2|
+-+-+
 
     1 append 2 3 4
+-+-------+
|1|+-+-+-+|
| ||2|3|4||
| |+-+-+-+|
+-+-------+
 
     1 2 3 append 4
+-+-+-+-+
|1|2|3|4|
+-+-+-+-+

10. Funkce pro vygenerování polí

Další sada funkcí slouží pro vygenerování celého pole na základě zvoleného algoritmu.

Vytvoření jednorozměrného pole se sekvencí hodnot začínajících buď od nuly (tell) nebo od jedničky (count):

     tell 10
+-+-+-+-+-+-+-+-+-+-+
|0|1|2|3|4|5|6|7|8|9|
+-+-+-+-+-+-+-+-+-+-+
 
     count 10
+-+-+-+-+-+-+-+-+-+--+
|1|2|3|4|5|6|7|8|9|10|
+-+-+-+-+-+-+-+-+-+--+

V případě, že budeme chtít odlišnou sekvenci, můžeme použít výpočty s poli:

     1 + count 10
+-+-+-+-+-+-+-+-+--+--+
|2|3|4|5|6|7|8|9|10|11|
+-+-+-+-+-+-+-+-+--+--+
 
     count 10 + count 10
+-+-+-+-+--+--+--+--+--+--+
|2|4|6|8|10|12|14|16|18|20|
+-+-+-+-+--+--+--+--+--+--+

Konstrukce dvourozměrného pole kombinací reshape a count/tell:

     3 4 reshape count 12
+-+--+--+--+
|1| 2| 3| 4|
+-+--+--+--+
|5| 6| 7| 8|
+-+--+--+--+
|9|10|11|12|
+-+--+--+--+
 
     3 4 reshape tell 12
+-+-+--+--+
|0|1| 2| 3|
+-+-+--+--+
|4|5| 6| 7|
+-+-+--+--+
|8|9|10|11|
+-+-+--+--+

Další možnosti:

     3 4 reshape count 12 + 100
+---+---+---+---+
|101|102|103|104|
+---+---+---+---+
|105|106|107|108|
+---+---+---+---+
|109|110|111|112|
+---+---+---+---+

Získat je možné i pole s indexy (adresami) prvků původního pole:

     grid 1 2
+-+-+
|0|1|
+-+-+
 
     grid 1 2 3
+-+-+-+
|0|1|2|
+-+-+-+
 
     grid 3 4 2 1
+-+-+-+-+
|0|1|2|3|
+-+-+-+-+
 
     grid (3 4 reshape 12)
+-----+-----+-----+-----+
|+-+-+|+-+-+|+-+-+|+-+-+|
||0|0|||0|1|||0|2|||0|3||
|+-+-+|+-+-+|+-+-+|+-+-+|
+-----+-----+-----+-----+
|+-+-+|+-+-+|+-+-+|+-+-+|
||1|0|||1|1|||1|2|||1|3||
|+-+-+|+-+-+|+-+-+|+-+-+|
+-----+-----+-----+-----+
|+-+-+|+-+-+|+-+-+|+-+-+|
||2|0|||2|1|||2|2|||2|3||
|+-+-+|+-+-+|+-+-+|+-+-+|
+-----+-----+-----+-----+

A konečně si ukažme, jak lze vytvořit pole s pseudonáhodnými hodnotami:

     random 10
0.726391 0.448169 0.384064 0.961273 0.123186 0.384953 0.911016 0.44919 0.536883 0.385413

Změna rozsahu pseudonáhodných hodnot:

     10 * random 20
0.124268 8.57941 4.22553 8.50044 6.85217 4.47933 4.07353 3.74976 2.13688 4.55871
 8.20644 5.64311 3.67626 6.82072 5.87837 7.69379 9.57127 4.40364 1.92131 1.42347

Vygenerování náhodných hodnot od 0 do 9:

     floor(10 * random 20)
4 8 4 4 6 7 7 6 8 2 4 1 0 3 9 7 3 8 8 7

Dosazení pole do proměnné:

     x is floor(10 * random 20)
     x
8 6 2 1 0 0 5 6 5 4 2 6 5 3 1 6 5 4 5 3

Dtto, ale pro dvourozměrné pole:

     random 5 5
+----------+--------+--------+--------+--------+
|  0.123186|0.384953|0.911016| 0.44919|0.536883|
+----------+--------+--------+--------+--------+
|  0.385413|0.639681|0.119586|0.882235| 0.72909|
+----------+--------+--------+--------+--------+
|  0.810901|0.819432|0.193461|0.498833|0.880408|
+----------+--------+--------+--------+--------+
|0.00925989|0.631015|0.476912|0.455139| 0.52156|
+----------+--------+--------+--------+--------+
|  0.851008|0.893033|0.210305|0.603614|0.940779|
+----------+--------+--------+--------+--------+

popř.:

     floor(10*random 10 10)
+-+-+-+-+-+-+-+-+-+-+
|8|2|6|9|6|2|6|7|5|6|
+-+-+-+-+-+-+-+-+-+-+
|2|6|0|6|1|9|7|1|1|6|
+-+-+-+-+-+-+-+-+-+-+
|3|8|5|8|1|7|7|6|0|7|
+-+-+-+-+-+-+-+-+-+-+
|2|9|5|2|4|8|2|2|3|7|
+-+-+-+-+-+-+-+-+-+-+
|7|9|2|3|0|3|7|8|1|2|
+-+-+-+-+-+-+-+-+-+-+
|6|8|3|6|9|1|8|3|3|1|
+-+-+-+-+-+-+-+-+-+-+
|5|0|0|6|8|9|3|2|5|8|
+-+-+-+-+-+-+-+-+-+-+
|5|7|4|4|8|4|1|6|8|5|
+-+-+-+-+-+-+-+-+-+-+
|4|0|0|6|3|2|9|4|7|2|
+-+-+-+-+-+-+-+-+-+-+
|2|9|8|9|3|0|8|4|8|6|
+-+-+-+-+-+-+-+-+-+-+

11. Pole a relační operátory

Jazyk Nial umožňuje porovnání všech prvků pole s nějakou zadanou hodnotou. Výsledkem je potom nové pole, jehož prvky jsou pravdivostní hodnoty, jenž jsou ovšem v Nialu reprezentovány znaky l (true) a o (false). To je netradiční reprezentace pravdivostních hodnot, na druhou stranu je však jisté, že tyto hodnoty budou uloženy v jediném bajtu a nikoli například jako celé 32bitové číslo:

     1=1
l
 
     1=2
o

Nejprve vytvoříme pole (zde vektor), který budeme testovat:

     x is count 10
     x
+-+-+-+-+-+-+-+-+-+--+
|1|2|3|4|5|6|7|8|9|10|
+-+-+-+-+-+-+-+-+-+--+

Porovnání všech prvků se zadanou hodnotou:

     x <= 5
+-+-+-+-+-+-+-+-+-+-+
|l|l|l|l|l|o|o|o|o|o|
+-+-+-+-+-+-+-+-+-+-+
 
     x >= 5
+-+-+-+-+-+-+-+-+-+-+
|o|o|o|o|l|l|l|l|l|l|
+-+-+-+-+-+-+-+-+-+-+
 
     5 < x
+-+-+-+-+-+-+-+-+-+-+
|o|o|o|o|o|l|l|l|l|l|
+-+-+-+-+-+-+-+-+-+-+
 

Stejnou operaci je možné provést i s dvourozměrným polem:

     x is 5 5 reshape count 25
     x
 
 1  2  3  4  5
 6  7  8  9 10
11 12 13 14 15
16 17 18 19 20
21 22 23 24 25
 
     x <= 12
lllll
lllll
llooo
ooooo
ooooo
Poznámka: velký pozor si musíme dát na to, že pomocí = resp. jeho negace ~= se provádí odlišná operace – test, jestli jsou dvě pole zcela stejná či naopak rozdílná:
     x is count 10
     y is count 10
     x = y
l
 
     x ~= y
o

A pro nepatrně odlišná pole, která se od sebe odlišují jediným prvkem:

     x is count 10
     y is 1 2 3 4 -5 6 7 8 9
     x
+-+-+-+-+-+-+-+-+-+--+
|1|2|3|4|5|6|7|8|9|10|
+-+-+-+-+-+-+-+-+-+--+
 
     y
+-+-+-+-+--+-+-+-+-+
|1|2|3|4|-5|6|7|8|9|
+-+-+-+-+--+-+-+-+-+
 
     x = y
o
 
     x ~= y
l

12. Funkce operující s celým polem

Některé funkce, které nalezneme ve standardní knihovně jazyka Nial, operují s celým polem, resp. přesněji řečeno se u většiny těchto funkcí předpokládá, že se bude jednat o vektory nebo matice. Dále popsané funkce budeme testovat s následujícím polem (konkrétně s dvourozměrnou maticí):

     x is 2 3 reshape count 6
     x
+-+-+-+
|1|2|3|
+-+-+-+
|4|5|6|
+-+-+-+

Transpozice matice je realizována funkcí transpose:

     transpose x
+-+-+
|1|4|
+-+-+
|2|5|
+-+-+
|3|6|
+-+-+

Rotace prvků doprava (první operand je záporný) nebo doleva (první operand je kladný). Povšimněte si, že prvky jsou v poli posouvány nejenom v rámci sloupců, ale překračují i řádky:

     -1 rotate x
+-+-+-+
|6|1|2|
+-+-+-+
|3|4|5|
+-+-+-+
 
     -2 rotate x
+-+-+-+
|5|6|1|
+-+-+-+
|2|3|4|
+-+-+-+
 
     -3 rotate x
+-+-+-+
|4|5|6|
+-+-+-+
|1|2|3|
+-+-+-+
 
     1 rotate x
+-+-+-+
|2|3|4|
+-+-+-+
|5|6|1|
+-+-+-+

Otočení všech prvků ve vektoru nebo matici:

     reverse x
+-+-+-+
|6|5|4|
+-+-+-+
|3|2|1|
+-+-+-+

Tato operace je zvláště výhodná u vektorů:

     reverse count 10
+--+-+-+-+-+-+-+-+-+-+
|10|9|8|7|6|5|4|3|2|1|
+--+-+-+-+-+-+-+-+-+-+

13. Pole jakožto rekurzivní datová struktura

Vzhledem k tomu, že pole mohou jako své prvky obsahovat další pole, je možné v programovacím jazyce Nial tvořit i dosti složité datové struktury. Podívejme se například na vytvoření pole, v němž každý prvek obsahuje další pole, konkrétně dvojice celočíselných prvků:

     count 10 + [1 2]
 
+-----+-----+-----+-----+-----+-----+-----+------+-------+-------+
|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+--+|+--+--+|+--+--+|
||2|3|||3|4|||4|5|||5|6|||6|7|||7|8|||8|9|||9|10|||10|11|||11|12||
|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+-+|+-+--+|+--+--+|+--+--+|
+-----+-----+-----+-----+-----+-----+-----+------+-------+-------+

Podobným způsobem lze realizovat i složitější matice, jejichž prvky jsou pole:

     3 4 reshape count 12 + [10 10 10 10]
 
+-------------+-------------+-------------+-------------+
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
||11|11|11|11|||12|12|12|12|||13|13|13|13|||14|14|14|14||
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
+-------------+-------------+-------------+-------------+
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
||15|15|15|15|||16|16|16|16|||17|17|17|17|||18|18|18|18||
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
+-------------+-------------+-------------+-------------+
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
||19|19|19|19|||20|20|20|20|||21|21|21|21|||22|22|22|22||
|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|+--+--+--+--+|
+-------------+-------------+-------------+-------------+

Pro zápis složitějších struktur můžeme použít i notaci, které silně připomíná LISPovské jazyky. Povšimněte si, jak zápis se závorkami přesně odpovídá výsledné datové struktuře:

     (1)
1
 
     (1 2)
+-+-+
|1|2|
+-+-+
 
     (1 (2 3))
+-+-----+
|1|+-+-+|
| ||2|3||
| |+-+-+|
+-+-----+
 
     (1 (2 (3 4 5 6)))
+-+-------------+
|1|+-+---------+|
| ||2|+-+-+-+-+||
| || ||3|4|5|6|||
| || |+-+-+-+-+||
| |+-+---------+|
+-+-------------+
 
     (1 (2 (3 4 5 6) 7) 8)
+-+---------------+-+
|1|+-+---------+-+|8|
| ||2|+-+-+-+-+|7|| |
| || ||3|4|5|6|| || |
| || |+-+-+-+-+| || |
| |+-+---------+-+| |
+-+---------------+-+
 
     (1 2 (3 4 5 6) 7 8)
+-+-+---------+-+-+
|1|2|+-+-+-+-+|7|8|
| | ||3|4|5|6|| | |
| | |+-+-+-+-+| | |
+-+-+---------+-+-+
 
     (1 2 (3 4) (5 6) 7 8)
+-+-+-----+-----+-+-+
|1|2|+-+-+|+-+-+|7|8|
| | ||3|4|||5|6|| | |
| | |+-+-+|+-+-+| | |
+-+-+-----+-----+-+-+

Přičtení hodnoty 100 ke všem prvkům pole je vlastně rekurzivní operací, protože například přičtení ke třetímu prvku znamená operaci (103 104) + 100 atd.:

     (1 2 (3 4) (5 6) 7 8) + 100
+---+---+---------+---------+---+---+
|101|102|+---+---+|+---+---+|107|108|
|   |   ||103|104|||105|106||   |   |
|   |   |+---+---+|+---+---+|   |   |
+---+---+---------+---------+---+---+

Totéž platí i pro řetězce:

     1 'abc' 'def'
+-+-------+-------+
|1|+-+-+-+|+-+-+-+|
| ||a|b|c|||d|e|f||
| |+-+-+-+|+-+-+-+|
+-+-------+-------+

Alternativní způsoby zápisu:

     [1 [2 3] 4]
+-----------+
|+-+-----+-+|
||1|+---+|4||
|| ||2 3|| ||
|| |+---+| ||
|+-+-----+-+|
+-----------+
 
     [1 [2 3] 4] + count 4
+-----------+-----------+-----------+-----------+
|+-+-----+-+|+-+-----+-+|+-+-----+-+|+-+-----+-+|
||2|+---+|5|||3|+---+|6|||4|+---+|7|||5|+---+|8||
|| ||3 4|| ||| ||4 5|| ||| ||5 6|| ||| ||6 7|| ||
|| |+---+| ||| |+---+| ||| |+---+| ||| |+---+| ||
|+-+-----+-+|+-+-----+-+|+-+-----+-+|+-+-----+-+|
+-----------+-----------+-----------+-----------+
 
     2 2 reshape ([1 [2 3] 4] + count 4)
+-----------+-----------+
|+-+-----+-+|+-+-----+-+|
||2|+---+|5|||3|+---+|6||
|| ||3 4|| ||| ||4 5|| ||
|| |+---+| ||| |+---+| ||
|+-+-----+-+|+-+-----+-+|
+-----------+-----------+
|+-+-----+-+|+-+-----+-+|
||4|+---+|7|||5|+---+|8||
|| ||5 6|| ||| ||6 7|| ||
|| |+---+| ||| |+---+| ||
|+-+-----+-+|+-+-----+-+|
+-----------+-----------+

14. Zobecněný outer product

S využitím operátoru outer product, s nímž jsme se již setkali při popisu jazyka APL a jenž umožňuje z dvojice vektorů vytvořit matici (a jedná se o jednu z jeho nejlepších vlastností) 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. Povšimněte si, jakým způsobem se tyto funkce musí zapsat:

     # vektor s prvky 1 až 5
     x is count 5
 
     # malá násobilka
     x outer * x
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
 
     # první pokus o vytvoření jednotkové matice
     x outer = x
loooo
olooo
ooloo
ooolo
ooool
 
     # druhý pokus o vytvoření jednotkové matice
     1 * (x outer = x)
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
 
     # trojúhelníková matice
     1 * (x outer <= x)
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
 
     # odlišná trojúhelníková matice
     1 * (x outer >= x)
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

Použít samozřejmě můžeme dva odlišné vstupní vektory:

     x is count 10
     y is count 5
 
     x outer * y
 
 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
 6 12 18 24 30
 7 14 21 28 35
 8 16 24 32 40
 9 18 27 36 45
10 20 30 40 50
 
     y outer * x
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

15. Zobecněný skalární součin (inner product)

Programovací jazyk Nial, ostatně jako většina ostatních jazyků odvozených od APL, podporuje i výpočet zobecněného skalárního součinu. Připomeňme si, že klasický skalární součin spočívá v tom, že se vynásobí odpovídající prvky dvou vektorů (tedy první prvek z prvního vektoru s prvním prvkem druhého vektoru atd.) a výsledná sekvence hodnot se sečte. Zobecnění spočívá v tom, že jak násobení, tak i výsledný součet je zcela volitelnou operací, což má dalekosáhlé důsledky (ostatně jak zobecněný skalární součin, tak i zobecněný vnější součin jsou velmi silnými zbraněmi „APL jazyků“). Podívejme se nyní, jak je skalární součin zapisován v Nialu, zejména jak se specifikují obě operace:

Klasický skalární součin:

     x is count 10
     x inner [*,+] x
385

Otočení pořadí obou operací (odpovídající prvky jsou sečteny, výsledky vynásobeny):

     x inner [*,+] x
3715891200

Výpočet, kolik prvků ve dvou vektorech si odpovídá (lze využít pro vyhledávání řetězců atd.):

     1 2 3 4 inner [+,=] 1 9 8 4
2

Test na úplnou rovnost prvků dvou vektorů:

     1 2 3 4 inner [and,=] 1 1 1 1
o
 
     1 2 3 4 inner [and,=] 1 2 3 4
l

Ovšem vstupem nemusí být jen vektory, ale i matice. Například takto lze nahradit operaci maticového součinu:

     t1 is 3 2 reshape count 6
     t2 is 2 4 reshape count 8
 
     t1
1 2
3 4
5 6
 
     t2
1 2 3 4
5 6 7 8
 
     t1 inner [+,*] t2
11 14 17 20
23 30 37 44
35 46 57 68

16. Další ukázky práce s poli

V této kapitole jsou uvedeny některé ukázky práce s poli, které se tematicky nehodily do předchozích kapitol.

Konstrukce nulové matice a získání tvaru této matice:

     x is 3 4 reshape 0
 
     x
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
|0|0|0|0|
+-+-+-+-+
 
     shape x
+-+-+
|3|4|
+-+-+

Vytvoření trojrozměrného pole (povšimněte si způsobu jeho zobrazení):

     x is 4 3 2 reshape count 24
 
     x
+-+-+  +--+--+  +--+--+  +--+--+
|1|2|  | 7| 8|  |13|14|  |19|20|
+-+-+  +--+--+  +--+--+  +--+--+
|3|4|  | 9|10|  |15|16|  |21|22|
+-+-+  +--+--+  +--+--+  +--+--+
|5|6|  |11|12|  |17|18|  |23|24|
+-+-+  +--+--+  +--+--+  +--+--+
 
     shape x
+-+-+-+
|4|3|2|
+-+-+-+

Součin prvek po prvku (nejedná se o maticový součin!):

     x*x
+--+--+  +---+---+  +---+---+  +---+---+
| 1| 4|  | 49| 64|  |169|196|  |361|400|
+--+--+  +---+---+  +---+---+  +---+---+
| 9|16|  | 81|100|  |225|256|  |441|484|
+--+--+  +---+---+  +---+---+  +---+---+
|25|36|  |121|144|  |289|324|  |529|576|
+--+--+  +---+---+  +---+---+  +---+---+

Konstrukce šestirozměrného pole 2×2×2×2×2×2 prvky:

     2 2 2 2 2 2 reshape count 64
 
+-+-+    +-+-+      +--+--+  +--+--+
|1|2|    |5|6|      |17|18|  |21|22|
+-+-+    +-+-+      +--+--+  +--+--+
|3|4|    |7|8|      |19|20|  |23|24|
+-+-+    +-+-+      +--+--+  +--+--+

+--+--+  +--+--+    +--+--+  +--+--+
| 9|10|  |13|14|    |25|26|  |29|30|
+--+--+  +--+--+    +--+--+  +--+--+
|11|12|  |15|16|    |27|28|  |31|32|
+--+--+  +--+--+    +--+--+  +--+--+
 
 
+--+--+  +--+--+    +--+--+  +--+--+
|33|34|  |37|38|    |49|50|  |53|54|
+--+--+  +--+--+    +--+--+  +--+--+
|35|36|  |39|40|    |51|52|  |55|56|
+--+--+  +--+--+    +--+--+  +--+--+
 
+--+--+  +--+--+    +--+--+  +--+--+
|41|42|  |45|46|    |57|58|  |61|62|
+--+--+  +--+--+    +--+--+  +--+--+
|43|44|  |47|48|    |59|60|  |63|64|
+--+--+  +--+--+    +--+--+  +--+--+

Funkce display zobrazí pole tak, jak by se dalo zapsat zpět do terminálu pro jeho konstrukci (jedná se tedy vlastně o serializaci):

     x is 2 3 reshape count 6
 
     x
1 2 3
4 5 6
 
     display x
2 3 reshape 1 2 3 4 5 6

Dtto pro jiné pole:

     x is 2 2 2 2 2 2 reshape count 64
 
     display x
 
2 2 2 2 2 2 reshape 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
 51 52 53 54 55 56 57 58 59 60 61 62 63 64

Odlišný (řekněme alternativní) způsob předání parametrů funkcím, který se podobá běžným programovacím jazykům:

     reshape [3 4,count 12]
+-+--+--+--+
|1| 2| 3| 4|
+-+--+--+--+
|5| 6| 7| 8|
+-+--+--+--+
|9|10|11|12|
+-+--+--+--+
 
     sum[reshape [3 4,count 12], 100]
+---+---+---+---+
|101|102|103|104|
+---+---+---+---+
|105|106|107|108|
+---+---+---+---+
|109|110|111|112|
+---+---+---+---+

17. Definice funkcí

Velmi elegantně je v programovacím jazyku Nial vyřešena problematika definice funkcí. Plně je pochopitelně podporována programovací technika tacit programming, ale i částečná realizace funkcí atd.

Příkladem může být definice funkce pro přičtení jedničky k operandu:

     inc is (1 +)

Jedná se o plnohodnotnou funkci s jediným operandem:

     inc 10
11
 
     inc 1 2 3 4
2 3 4 5

Příkladem využití tacit programmingu může být definice funkce pro výpočet faktoriálu, jejíž tělo je tvořeno nedokončeným výrazem, kterému je zapotřebí předat počet prvků pro funkci count:

     fact is * count
 
     fact 10
3628800

Faktoriál lze ovšem realizovat i klasickým rekurzivním výpočtem – všechna důležitá klíčová slova jsou podporována:

     fact2 is op x {if x = 0 then 1 else x * fact (x - 1) endif}
 
     fact2 10
3628800

V definici funkce fact2 je specifikováno, že akceptuje jeden operand. Ovšem velmi snadno lze realizovat funkci s oběma operandy:

     add is op x y {x + y}

Funkce se posléze použije stejně, jako jakákoli další „operátorová funkce“ se dvěma operandy:

zabbix_tip

     1 add 2
3
 
     1 2 3 add 3 4 5
4 6 8

18. Závěrečné zhodnocení

Jak jsme si již v dnešním článku několikrát řekli, patří Nial mezi programovací jazyky, které zcela evidentně přebírají myšlenky z APL a do jisté míry i z funkcionálních programovacích jazyků. Nial se ovšem i přes svoje stáří nikdy nerozšířil mezi mainstream a pravděpodobně k tomu ani nedojde – nejvíce se v této oblasti používá APL (přesněji řečeno jeho varianta nazvaná Dyalog) a taktéž programovací jazyk Q odvozený od K (jehož pozice je v dané nice neotřesitelná). Na druhou stranu se jedná (v porovnání s konkurencí) o velmi čitelný jazyk, takže by se mohlo jednat o dobrou volbu pro ty vývojáře, kteří se chtějí seznámit se zajímavým světem array programmingu. Pokud vás ovšem zajímá, jak by mohl vypadat skutečně moderně pojatý jazyk z této oblasti, je podle mého názoru zajímavější se zaměřit na jazyk BQN, popř. zjistit, jak byly myšlenky převzaté z APL realizovány například v jazyku Julia.

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 APL, jsme se již na stránkách Roota zabývali v několika článcích. Odkazy na tyto články naleznete pod odstavcem:

  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. Specializované jazyky pro práci s N-dimenzionálními poli: jazyk J
    https://www.root.cz/clanky/spe­cializovane-jazyky-pro-praci-s-n-dimenzionalnimi-poli-jazyk-j/
  3. Programovací jazyky odvozené od APL: BQN a ivy aneb 1~×`1↓↕10
    https://www.root.cz/clanky/pro­gramovaci-jazyky-odvozene-od-apl-bqn-a-ivy-aneb-1–1–10/
  4. Programovací jazyk K: důkaz, že mezi námi žijí mimozemšťané
    https://www.root.cz/clanky/pro­gramovaci-jazyk-k-dukaz-ze-mezi-nami-ziji-mimozemstane/
  5. Programovací jazyk K: důkaz, že mezi námi žijí mimozemšťané (dokončení)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-k-dukaz-ze-mezi-nami-ziji-mimozemstane-dokonceni/
  6. Programování mainframů: jazyk APL
    https://www.root.cz/clanky/pro­gramovani-mainframu-jazyk-apl/
  7. Programovací jazyk APL: programování bez smyček
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-programovani-bez-smycek/
  8. Programovací jazyk APL – dokončení
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-dokonceni/
  9. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/

20. Odkazy na Internetu

  1. Nial: A powerful, interactive array language with support for flexible multiparadigm code
    https://www.nial-array-language.org/
  2. Nial: dokumentace
    https://www.nial-array-language.org/ndocs/
  3. Nial na GitHubu
    https://github.com/niallan­g/Nial_Development
  4. Nial na Rosetta Code
    https://rosettacode.org/wi­ki/Category:Nial
  5. Array language comparisons
    https://github.com/codereport/array-language-comparisons
  6. K language – an introduction
    http://www.math.bas.bg/ban­tchev/place/k.html
  7. K7 Tutorial
    https://cs.nyu.edu/~shasha/pa­pers/tutorial
  8. An Interview with Arthur Whitney, Kx CEO and Developer of Kx Technology, January 4, 2004
    https://web.archive.org/web/20150813004101/htt­p://kx.com/arthur-interview.php
  9. A Shallow Introduction to the K Programming Language
    https://web.archive.org/web/20130801233812/htt­p://www.kuro5hin.org/story/2002/11/14/22741/791
  10. A Conversation with Arthur Whitney
    https://queue.acm.org/deta­il.cfm?id=1531242
  11. Anecdote about Arthur Whitney
    https://news.ycombinator.com/i­tem?id=13590065
  12. K – list of idioms
    https://github.com/kevinlaw­ler/kona/wiki/Idioms
  13. Appendix A. Incunabulum
    http://keiapl.org/rhui/re­member.htm#incunabulum
  14. K code study
    https://docs.google.com/do­cument/d/1W83ME5JecI2hd5hA­UqQ1BVF32wtCel8zxb7WPq-D4f8/edit
  15. K tutorial
    https://github.com/kevinlaw­ler/kona/wiki/Tutorial
  16. K by EXAMPLE
    http://vrabi.web.elte.hu/k/kbyeg.k
  17. BQN: An APL Variant from Marshall Lochbaum (mlochbaum.github.io)
    https://news.ycombinator.com/i­tem?id=24167804
  18. Raytracer in 7 lines in K
    http://www.nsl.com/k/ray/ray.k
  19. Marshall Lochbaum
    https://www.aplwiki.com/wi­ki/Marshall_Lochbaum
  20. BQN
    https://www.aplwiki.com/wiki/BQN
  21. Co-dfns
    https://www.aplwiki.com/wiki/Co-dfns
  22. Array model
    https://www.aplwiki.com/wi­ki/Array_model#Based_arra­y_theory
  23. Fonts for BQN
    https://mlochbaum.github.i­o/BQN/fonts.html
  24. Leading axis theory
    https://www.aplwiki.com/wi­ki/Leading_axis_theory
  25. A based system for general arrays
    https://dl.acm.org/doi/ab­s/10.1145/586656.586663
  26. APL – A Glimpse of Heaven (2006)
    https://news.ycombinator.com/i­tem?id=19325361
  27. APL and J
    https://crypto.stanford.e­du/~blynn/c/apl.html
  28. ivy (dokumentace)
    https://pkg.go.dev/robpike­.io/ivy#section-readme
  29. ivy na GitHubu
    https://github.com/robpike/ivy/
  30. Ivy na APL wiki
    https://aplwiki.com/wiki/Ivy
  31. Implementing a bignum calculator (slajdy)
    https://talks.godoc.org/git­hub.com/robpike/ivy/talks/i­vy.slide#1
  32. Implementing a bignum calculator – Rob Pike – golang-syd November 2014
    https://www.youtube.com/wat­ch?v=PXoG0WX0r_E
  33. Rob Pike na Wikipedii
    https://en.wikipedia.org/wi­ki/Rob_Pike
  34. Rob Pike na cat-v
    http://genius.cat-v.org/rob-pike/
  35. 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/
  36. Programovací technika nazvaná tacit programming
    https://www.root.cz/clanky/pro­gramovaci-technika-nazvana-tacit-programming/
  37. Oslava 55 let od vzniku první implementace jazyka APL
    https://www.root.cz/clanky/oslava-55-let-od-vzniku-prvni-implementace-programovaciho-jazyka-apl/
  38. NuVoc
    https://code.jsoftware.com/wiki/NuVoc
  39. J (programming language) [Wikipedia]
    https://en.wikipedia.org/wi­ki/J_%28programming_langu­age%29
  40. J – Absolutely Essential Terms
    https://code.jsoftware.com/wi­ki/Vocabulary/AET
  41. J – Atoms and Arrays
    https://code.jsoftware.com/wi­ki/Vocabulary/Nouns#Atom
  42. Why J
    https://www.jsoftware.com/hel­p/primer/why_j.htm
  43. What is an Array?
    https://vector.org.uk/what-is-an-array/
  44. Comments
    http://www.gavilan.edu/csis/lan­guages/comments.html
  45. Vector (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Vector.html
  46. n-Tuple (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Tuple.html
  47. n-Vector (Wolfram MathWorld)
    https://mathworld.wolfram.com/n-Vector.html
  48. Matrix (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Matrix.html
  49. Array (Wolfram MathWorld)
    https://mathworld.wolfram­.com/Array.html
  50. ND Arrays (Tensors) in different languages
    https://www.youtube.com/wat­ch?v=WbpbEilgQBc
  51. Extending APL to Infinity\
    https://www.jsoftware.com/pa­pers/eem/infinity.htm
  52. Vector Library (R7RS-compatible)
    https://srfi.schemers.org/srfi-133/srfi-133.html
  53. Vectors (pro Gauche)
    https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html
  54. Kawa: Compiling Scheme to Java
    https://www.mit.edu/afs.new/sip­b/project/kawa/doc/kawa-tour.html
  55. Kawa in Languages shootout
    http://per.bothner.com/blog/2010/Kawa-in-shootout/
  56. Kawa 2.0 Supports Scheme R7RS
    https://developers.slashdot­.org/story/14/12/13/2259225/ka­wa-20-supports-scheme-r7rs/
  57. Kawa — fast scripting on the Java platform
    https://lwn.net/Articles/623349/
  58. Incanter is a Clojure-based, R-like platform for statistical computing and graphics.
    http://incanter.org/
  59. Evolution of incanter (Gource Visualization)
    https://www.youtube.com/wat­ch?v=TVfL5nPELr4
  60. Questions tagged [incanter] (na Stack Overflow)
    https://stackoverflow.com/qu­estions/tagged/incanter?sor­t=active
  61. Data Sorcery with Clojure
    https://data-sorcery.org/contents/
  62. 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
  63. Incanter Cheat Sheet
    http://incanter.org/docs/incanter-cheat-sheet.pdf
  64. 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
  65. BQN: finally, an APL for your flying saucer
    https://mlochbaum.github.io/BQN/
  66. Is BQN stable?
    https://mlochbaum.github.i­o/BQN/commentary/stability­.html
  67. Specification: BQN system-provided values
    https://mlochbaum.github.i­o/BQN/spec/system.html
  68. Tutorial: BQN expressions
    https://mlochbaum.github.i­o/BQN/tutorial/expression­.html
  69. BQN primitives
    https://mlochbaum.github.i­o/BQN/doc/primitive.html
  70. Function trains
    https://mlochbaum.github.i­o/BQN/doc/train.html
  71. BQN community links
    https://mlochbaum.github.i­o/BQN/community/index.html
  72. BQN UV
    https://observablehq.com/@lsh/bqn-uv
  73. APL Wiki
    https://aplwiki.com/wiki/
  74. The Array Cast
    https://www.arraycast.com/e­pisodes/episode-03-what-is-an-array
  75. EnthusiastiCon 2019 – An Introduction to APL
    https://www.youtube.com/wat­ch?v=UltnvW83_CQ
  76. Dyalog
    https://www.dyalog.com/
  77. Try APL!
    https://tryapl.org/
  78. Lisp-Stat Information
    http://homepage.cs.uiowa.e­du/~luke/xls/xlsinfo/
  79. Sample Plots in Incanter
    https://github.com/incanter/in­canter/wiki/Sample-Plots-in-Incanter#line
  80. vectorz-clj
    https://github.com/mikera/vectorz-clj
  81. vectorz – Examples
    https://github.com/mikera/vectorz-clj/wiki/Examples
  82. 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
  83. Vectors and matrices in Julia
    https://fncbook.github.io/v1­.0/linsys/demos/matrices-julia.html
  84. Array vs Matrix in R Programming
    https://www.geeksforgeeks.org/array-vs-matrix-in-r-programming/
  85. Concurrency (computer science)
    https://en.wikipedia.org/wi­ki/Category:Concurrency_%28com­puter_science%29
  86. Koprogram
    https://cs.wikipedia.org/wi­ki/Koprogram
  87. Coroutine
    https://en.wikipedia.org/wi­ki/Coroutine
  88. Coroutines in C
    http://www.chiark.greenen­d.org.uk/~sgtatham/corouti­nes.html
  89. S-expression (Wikipedia)
    https://en.wikipedia.org/wiki/S-expression
  90. S-Expressions (Rosetta Code)
    http://rosettacode.org/wiki/S-Expressions
  91. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  92. Tutorial for the Common Lisp Loop Macro
    http://www.ai.sri.com/pkarp/loop.html
  93. 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
  94. Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html
  95. Clojure Macro Tutorial (Part III: Syntax Quote)
    http://www.learningclojure­.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html
  96. Clojure Macros and Metaprogramming
    http://clojure-doc.org/articles/language/macros.html
  97. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  98. CS 2101 Parallel Computing with Julia
    https://www.coursehero.com/fi­le/11508091/CS-2101-Parallel-Computing-with-Julia/
  99. Julia By Example
    https://samuelcolvin.github­.io/JuliaByExample/
  100. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  101. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  102. no stinking loops – Kalothi
    http://www.nsl.com/
  103. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  104. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  105. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  106. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  107. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  108. A+
    http://www.aplusdev.org/
  109. APLX
    http://www.microapl.co.uk/
  110. FreeAPL
    http://www.pyr.fi/apl/index.htm
  111. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  112. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  113. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  114. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  115. Parrot APL (GPL)
    http://www.parrotcode.org/
  116. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  117. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  118. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  119. Introducing Julia/Functions
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Functi­ons
  120. Functions (Julia documentation)
    https://docs.julialang.or­g/en/v1/manual/functions/
  121. Evaluate binomial coefficients
    http://rosettacode.org/wi­ki/Evaluate_binomial_coef­ficients
  122. Ackermann function
    http://rosettacode.org/wi­ki/Ackermann_function
  123. Julia (front page)
    http://julialang.org/
  124. Julia – dokumentace
    http://docs.julialang.org/
  125. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  126. Julia (programming language)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  127. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  128. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  129. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  130. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  131. Learn X in Y minutes (where X=Julia)
    https://learnxinyminutes.com/doc­s/julia/
  132. 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
  133. Julia: A Fast Dynamic Language for Technical Computing
    http://karpinski.org/publi­cations/2012/julia-a-fast-dynamic-language
  134. The LLVM Compiler Infrastructure
    http://llvm.org/
  135. Julia: benchmarks
    http://julialang.org/benchmarks/
  136. Type system
    https://en.wikipedia.org/wi­ki/Type_system
  137. Half-precision floating-point format
    https://en.wikipedia.org/wiki/Half-precision_floating-point_format
  138. Dartmouth BASIC
    https://en.wikipedia.org/wi­ki/Dartmouth_BASIC
  139. BASIC 4th Edition
    http://www.bitsavers.org/pdf/dar­tmouth/BASIC_4th_Edition_Jan68­.pdf
  140. VECTRAN
    https://encyclopedia2.the­freedictionary.com/VECTRAN
  141. Comparison of programming languages (array)
    https://en.wikipedia.org/wi­ki/Comparison_of_programmin­g_languages_(array)
  142. BASIC at 50
    https://www.dartmouth.edu/ba­sicfifty/commands.html
  143. BBC Basic – arrays
    http://www.riscos.com/sup­port/developers/bbcbasic/par­t2/arrays.html
  144. Datová struktura
    https://cs.wikipedia.org/wi­ki/Datov%C3%A1_struktura
  145. SIMD instrukce využívané v moderních mikroprocesorech řady x86
    https://www.root.cz/clanky/simd-instrukce-vyuzivane-v-modernich-mikroprocesorech-rady-x86/
  146. 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/
  147. 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/
  148. Inductive type
    https://en.wikipedia.org/wi­ki/Inductive_type
  149. JuliaMono, a font for programming
    https://github.com/cormulli­on/juliamono
  150. It’s arrays all the way down
    https://xpqz.github.io/le­arnapl/array.html
  151. APL vs BQN vs J vs Q vs NumPy vs Julia vs R
    https://www.youtube.com/wat­ch?v=8ynsN4nJxzU

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.