Obsah
1. Podpora funkcionálního programovaní v jazyku Lua s využitím knihovny Moses
2. Instalace knihovny Moses a první testy
3. Import funkcí poskytovaných knihovnou Moses v rámci zvoleného kontextu
4. Funkce pro vytvoření sekvencí (konstruktory polí)
7. Získání n prvních popř. n posledních prvků z pole
8. Získání části pole funkcemi initial a rest
9. Pole využité jako množiny, množinové operace
13. Řez polem s využitím operace slice
14. Získání unikátních prvků v poli
15. Výběr prvků ze začátku pole funkcí vyššího řádu selectWhile
16. Přeskočení prvků ze začátku pole funkcí vyššího řádu dropWhile
17. Výběr prvků z pole s využitím funkce vyššího řádu filter
18. Repositář s demonstračními příklady
19. Články o programovacím jazyce Lua i o technologii LuaJITu
1. Podpora funkcionálního programovaní v jazyku Lua s využitím knihovny Moses
Na předchozí dva články [1] [2], v nichž jsme si ukazovali některé možnosti nabízené knihovnou Lua Fun v oblasti funkcionálního programování a zpracování konečných i nekonečných sekvencí, dnes navážeme. Popíšeme si totiž knihovnu nazvanou Moses, jejíž cíl je přibližně stejný – umožnit, aby se v programovacím jazyku Lua používaly programové konstrukce vycházející z funkcionálního programování: zpracování sekvencí (typicky bez modifikace původní sekvence), použití funkcí vyššího řádu apod. Zatímco knihovna Lua Fun byla navržena s ohledem na dosažení co nejlepšího výpočetního výkonu při jejím spuštění v LuaJITu, je zaměření knihovny Moses spíše obecnější, takže výpočty a operace v ní provedené mohou být pomalejší. Ostatně knihovna Moses je větší i co do objemu programového kódu, protože její čitelná verze má velikost přibližně 91 kB a minifikovaná verze 32 kB, zatímco čitelná verze knihovny Lua Fun má velikost 28 kB (bez minifikace).
Navíc je již z prvního porovnání obou knihoven patrné, že Lua Fun je založena na iterátorech a generátorech konečných či nekonečných sekvencí, zatímco Moses lze chápat spíše jako sadu užitečných operací pro zpracování tabulek, polí (což bychom spíš měli překládat jako seznamy) a objektů. Navíc zde ovšem nalezneme i funkci memoize, jíž lze použít pro zapamatování předchozích výsledků volání nějaké funkce (která by pochopitelně měla být referenčně transparentní). Proto bude popis knihovny Moses organizován poněkud jiným způsobem, než tomu bylo u knihovny Lua Fun. V knihovně Moses musíme především rozlišovat operace určené pro práci s poli (array), které jsou odlišné od funkcí pro práci s tabulkami (table). Použitá terminologie ovšem může být matoucí, protože array zde znamená seznam (list) a pro některé operace množinu (set), kdežto tabulka znamená slovník (dictionary):
# | Termín použitý v Moses | Běžný význam |
---|---|---|
1 | array | list, set |
2 | table | dictionary |
2. Instalace knihovny Moses a první testy
Většinu „funkcionálních“ pojmů, s nimiž se v dnešním článku setkáme, jsme si již popsali v úvodním článku, takže se dnes již můžeme zaměřit na ukázání způsobů použití této knihovny. Nejdříve ji pochopitelně musíme získat, což je ve skutečnosti velmi snadné. Postačuje použít Git pro naklonování repositáře projektu:
$ git clone git://github.com/Yonaba/Moses.git Cloning into 'Moses'... remote: Enumerating objects: 2017, done. remote: Total 2017 (delta 0), reused 0 (delta 0), pack-reused 2017 Receiving objects: 100% (2017/2017), 1.41 MiB | 1.79 MiB/s, done. Resolving deltas: 100% (1180/1180), done.
V naklonovaném repositáři se nachází zdrojové soubory této knihovny uložené v souboru se jménem moses.lua, popř. minifikovaná varianta pojmenovaná moses_min.lua. Jeden z těchto souborů postačuje přidat buď přímo ke zdrojovým kódům aplikace nebo do adresáře, na který ukazuje proměnná prostředí LUAPATH.
Pochopitelně je možné pro instalaci použít i správce balíčků LuaRocks.
Po instalaci je možné otestovat, zda je možné knihovnu Moses načíst do skriptu a použít funkce, které jsou v ní definovány:
-- načtení knihovny Moses local M = require "moses" -- pokus o použití funkce z knihovny Moses table = M.range(10, 1) for index, value in ipairs(table) do print(index, value) end
Výsledný skript by měl být spustitelný (resp. přesněji řečeno interpretovatelný):
$ lua 01_install_test.lua 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1
3. Import funkcí poskytovaných knihovnou Moses v rámci zvoleného kontextu
Existuje i druhá varianta importů funkcí, které jsou poskytované knihovnou Moses. Tato varianta je založena na tom, že se všechny funkce uloží buď do globálního jmenného prostoru (což je pro menší projekty užitečná vlastnost) nebo do zvoleného kontextu. Nejdříve si ukažme import funkcí do globálního jmenného prostoru. Pro tento účel se použije funkce import, které se nepředají žádné parametry:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- pokus o použití funkce z knihovny Moses table = range(10, 1) for index, value in ipairs(table) do print(index, value) end
I tento skript by měl být interpretrem bez problémů spustitelný:
$ lua 02_import_everything.lua 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1
Alternativně lze využít import funkcí do takzvaného kontextu, což může být libovolná (i prázdná) tabulka. K importovaným funkcím se bude přistupovat přes tečkovou notaci popř. výběrem přes klíč (což ovšem málokdo bude zapisovat). V dalším příkladu jsou vytvořeny a využity dva kontexty:
-- vytvoření dvou kontextů context1 = {} context2 = {} -- načtení knihovny Moses M = require "moses" -- import funkcí do kontextů M.import(context1) M.import(context2) -- pokus o použití funkce z knihovny Moses print("M") table = M.range(10, 1) for index, value in ipairs(table) do print(index, value) end print() -- nyní vyzkoušíme stejnou funkci, ovšem v prvním kontextu print("context 1") table = context1.range(10, 1) for index, value in ipairs(table) do print(index, value) end print() -- nyní vyzkoušíme stejnou funkci, ovšem ve druhém kontextu print("context 2") table = context2.range(10, 1) for index, value in ipairs(table) do print(index, value) end
Výsledek po spuštění příkladu:
$ lua 03_import_into_context.lua M 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 context 1 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 context 2 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1
4. Funkce pro vytvoření sekvencí (konstruktory polí)
Podobně jako se v knihovně Lua Fun nacházelo několik funkcí určených pro konstrukci konečných i nekonečných sekvencí, nalezneme v knihovně Moses funkce pro konstrukci (konečných) polí – většina těchto funkcí tedy potřebuje znát i informaci o délce nově konstruovaného pole. Jedná se o následující konstruktory:
# | Funkce | Význam |
---|---|---|
1 | zeros() | pole obsahující nulové prvky |
2 | ones() | pole obsahující prvky s hodnotou 1 |
3 | rep() | pole obsahující prvky se shodnou hodnotou předanou do konstruktoru |
4 | vector() | implementuje stejnou funkcionalitu, jako konstruktor rep |
5 | range() | pole s aritmetickou posloupností zadané délky |
První konstruktor se jmenuje zeros() a slouží pro vytvoření pole obsahujícího samé nuly (tedy N nulových prvků). Použití tohoto konstruktoru je snadné:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- pole s nulami a1 = zeros(10) printSeparator() print("zeros(10)") printArray(a1) -- pole s jedním prvkem a2 = zeros(1) printSeparator() print("zeros(1)") printArray(a2) -- prázdné pole s nulami a3 = zeros(0) printSeparator() print("zeros(0)") printArray(a3) -- pole s nulami a4 = zeros(-1) printSeparator() print("zeros(-1)") printArray(a4)
Výsledky zobrazené po spuštění tohoto demonstračního příkladu:
------------------------------- zeros(10) 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 ------------------------------- zeros(1) 1 0 ------------------------------- zeros(0) ------------------------------- zeros(-1)
Druhý konstruktor se jmenuje ones a slouží pro konstrukci pole obsahujícího pouze prvky s hodnotou 1:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- pole s jedničkami a1 = ones(10) printSeparator() print("ones(10)") printArray(a1) -- pole s jedním prvkem a2 = ones(1) printSeparator() print("ones(1)") printArray(a2) -- prázdné pole s jedničkami a3 = ones(0) printSeparator() print("ones(0)") printArray(a3) -- pole s jedničkami a4 = ones(-1) printSeparator() print("ones(-1)") printArray(a4)
Opět si ukažme zprávy zobrazené po spuštění tohoto demonstračního příkladu:
------------------------------- ones(10) 1 1 2 1 3 1 4 1 5 1 6 1 7 1 8 1 9 1 10 1 ------------------------------- ones(1) 1 1 ------------------------------- ones(0) ------------------------------- ones(-1)
Třetí konstruktor se jmenuje rep a slouží pro vytvoření pole se stejnými prvky. Tentokrát jsou ovšem prvky specifikované programátorem při volání konstruktoru. Ostatní chování je shodné s konstruktory zeros a ones:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- pole s opakující se hodnotou a1 = rep("*", 10) printSeparator() print("rep('*', 10)") printArray(a1) -- pole s jedinou hodnotou a2 = rep("*", 1) printSeparator() print("rep('*', 1)") printArray(a2) -- prázdné pole s opakující se hodnotou a3 = rep("*", 0) printSeparator() print("rep('*', 0)") printArray(a3) -- pole s opakující se hodnotou a4 = rep("*", -1) printSeparator() print("rep('*', -1)") printArray(a5)
Výsledky:
------------------------------- rep('*', 10) 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * ------------------------------- rep('*', 1) 1 * ------------------------------- rep('*', 0) ------------------------------- rep('*', -1)
Pole se stejnými vlastnostmi lze zkonstruovat i s využitím funkce vector, což opět vnáší určitý zmatek do použité terminologie (vektor má v jiných jazycích a knihovnách dosti odlišný význam). Z tohoto důvodu bude asi lepší použít výše zmíněný konstruktor rep:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- pole s opakující se hodnotou a1 = vector("*", 10) printSeparator() print("vector('*', 10)") printArray(a1) -- pole s jedinou hodnotou a2 = vector("*", 1) printSeparator() print("vector('*', 1)") printArray(a2) -- prázdné pole s opakující se hodnotou a3 = vector("*", 0) printSeparator() print("vector('*', 0)") printArray(a3) -- pole s opakující se hodnotou a4 = vector("*", -1) printSeparator() print("vector('*', -1)") printArray(a5)
Výsledky po spuštění:
------------------------------- vector('*', 10) 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10 * ------------------------------- vector('*', 1) 1 * ------------------------------- vector('*', 0) ------------------------------- vector('*', -1)
5. Konstruktor pole range
I v knihovně Moses pochopitelně nalezneme konstruktor range, který se ovšem některými svými vlastnostmi odlišuje od generátoru range z Pythonu či z knihovny Lua Fun. Konstruktor range akceptuje buď pouze zadání konečné hodnoty (potom se počítá od jedničky, jak je v jazyce Lua zvykem); lze ovšem zadat i počáteční hodnotu a navíc i krok. V případě, že je počáteční hodnota větší než hodnota koncová, bude krok automaticky nastaven na hodnotu –1, pochopitelně pokud není uveden explicitně. Navíc mohou být obě meze i krok specifikovány neceločíselnou hodnotou. Opět se podívejme na několik příkladů použití tohoto velmi užitečného konstruktoru:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- prázdné pole při neuvedení rozsahu a0 = range() printSeparator() print("range()") printArray(a0) -- první pole začínající standardně od jedničky a1 = range(10) printSeparator() print("range(10)") printArray(a1) -- druhé pole s explicitní specifikací hodnoty prvního prvku a2 = range(1, 10) printSeparator() print("range(1, 10)") printArray(a2) -- třetí pole se specifikací kroku (rozdílu mezi dvěma prvky) a3 = range(1, 10, 2) printSeparator() print("range(1, 10, 2)") printArray(a3) -- čtvrté pole s prvky počítanými pozpátku a4 = range(10, 1) printSeparator() print("range(10, 1)") printArray(a4) -- páté pole počítané pozpátku s kladným krokem a5 = range(10, 1, 2) printSeparator() print("range(10, 1, 2)") printArray(a5) -- šesté pole počítané pozpátku se záporným krokem a6 = range(10, 1, -2) printSeparator() print("range(10, 1, -2)") printArray(a6) -- sedmé pole s neceločíselným krokem a7 = range(1, 5, 0.5) printSeparator() print("range(10, 5, 0.5)") printArray(a7) -- osmé pole s neceločíselným krokem a počáteční hodnotou typu double a8 = range(1.0, 5, 0.5) printSeparator() print("range(10, 5, 0.5)") printArray(a8) -- deváté pole testující vliv problematické hodnoty 0.1 a9 = range(0, 1, 0.1) printSeparator() print("range(0, 1, 0.1)") printArray(a9) -- desáté pole s počáteční hodnotou typu double a10 = range(0.0, 1, 0.1) printSeparator() print("range(0.0, 1, 0.1)") printArray(a9)
S výsledky:
------------------------------- range() ------------------------------- range(10) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 ------------------------------- range(1, 10) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 ------------------------------- range(1, 10, 2) 1 1 2 3 3 5 4 7 5 9 ------------------------------- range(10, 1) 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 ------------------------------- range(10, 1, 2) 1 10 ------------------------------- range(10, 1, -2) 1 10 2 8 3 6 4 4 5 2 ------------------------------- range(10, 5, 0.5) 1 1 2 1.5 3 2.0 4 2.5 5 3.0 6 3.5 7 4.0 8 4.5 9 5.0 ------------------------------- range(10, 5, 0.5) 1 1.0 2 1.5 3 2.0 4 2.5 5 3.0 6 3.5 7 4.0 8 4.5 9 5.0 ------------------------------- range(0, 1, 0.1) 1 0 2 0.1 3 0.2 4 0.3 5 0.4 6 0.5 7 0.6 8 0.7 9 0.8 10 0.9 11 1.0 ------------------------------- range(0.0, 1, 0.1) 1 0 2 0.1 3 0.2 4 0.3 5 0.4 6 0.5 7 0.6 8 0.7 9 0.8 10 0.9 11 1.0
6. Získání otočeného pole
Tato kapitola bude velmi stručná, protože se v ní zmíníme o jediné funkci nazvané reverse. Tato funkce, jak již její název naznačuje, slouží pro získání nového pole, které obsahuje stejné prvky jako pole původní, ovšem uložené v opačném pořadí.
Podívejme se na příklad použití funkce reverse, a to na zdrojovém kódu, který vznikl nepatrnou úpravou předchozího demonstračního příkladu:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- prázdné pole při neuvedení rozsahu a0 = reverse(range()) printSeparator() print("reverse(range())") printArray(a0) -- první pole začínající standardně od jedničky a1 = reverse(range(10)) printSeparator() print("reverse(range(10))") printArray(a1) -- druhé pole s explicitní specifikací hodnoty prvního prvku a2 = reverse(range(1, 10)) printSeparator() print("reverse(range(1, 10))") printArray(a2) -- třetí pole se specifikací kroku (rozdílu mezi dvěma prvky) a3 = reverse(range(1, 10, 2)) printSeparator() print("reverse(range(1, 10, 2))") printArray(a3) -- čtvrté pole s prvky počítanými pozpátku a4 = reverse(range(10, 1)) printSeparator() print("reverse(range(10, 1))") printArray(a4) -- páté pole počítané pozpátku s kladným krokem a5 = reverse(range(10, 1, 2)) printSeparator() print("reverse(range(10, 1, 2))") printArray(a5) -- šesté pole počítané pozpátku se záporným krokem a6 = reverse(range(10, 1, -2)) printSeparator() print("reverse(range(10, 1, -2))") printArray(a6) -- sedmé pole s neceločíselným krokem a7 = reverse(range(1, 5, 0.5)) printSeparator() print("reverse(range(10, 5, 0.5))") printArray(a7) -- osmé pole s neceločíselným krokem a počáteční hodnotou typu double a8 = reverse(range(1.0, 5, 0.5)) printSeparator() print("reverse(range(10, 5, 0.5))") printArray(a8) -- deváté pole testující vliv problematické hodnoty 0.1 a9 = reverse(range(0, 1, 0.1)) printSeparator() print("reverse(range(0, 1, 0.1))") printArray(a9) -- desáté pole s počáteční hodnotou typu double a10 = reverse(range(0.0, 1, 0.1)) printSeparator() print("reverse(range(0.0, 1, 0.1))") printArray(a9)
Zprávy získané po spuštění tohoto příkladu:
------------------------------- reverse(range()) ------------------------------- reverse(range(10)) 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 ------------------------------- reverse(range(1, 10)) 1 10 2 9 3 8 4 7 5 6 6 5 7 4 8 3 9 2 10 1 ------------------------------- reverse(range(1, 10, 2)) 1 9 2 7 3 5 4 3 5 1 ------------------------------- reverse(range(10, 1)) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 ------------------------------- reverse(range(10, 1, 2)) 1 10 ------------------------------- reverse(range(10, 1, -2)) 1 2 2 4 3 6 4 8 5 10 ------------------------------- reverse(range(10, 5, 0.5)) 1 5.0 2 4.5 3 4.0 4 3.5 5 3.0 6 2.5 7 2.0 8 1.5 9 1 ------------------------------- reverse(range(10, 5, 0.5)) 1 5.0 2 4.5 3 4.0 4 3.5 5 3.0 6 2.5 7 2.0 8 1.5 9 1.0 ------------------------------- reverse(range(0, 1, 0.1)) 1 1.0 2 0.9 3 0.8 4 0.7 5 0.6 6 0.5 7 0.4 8 0.3 9 0.2 10 0.1 11 0 ------------------------------- reverse(range(0.0, 1, 0.1)) 1 1.0 2 0.9 3 0.8 4 0.7 5 0.6 6 0.5 7 0.4 8 0.3 9 0.2 10 0.1 11 0
7. Získání n prvních popř. n posledních prvků z pole
Při zpracování seznamů či sekvencí se často používají funkce nazvané first a rest. U polí je situace jednodušší, neboť je možné přistupovat k prvkům náhodně, je známá délka pole atd. Proto knihovna Moses nabízí následující funkce, které dokážou z pole získat prvky ze začátku nebo naopak z konce pole:
# | Funkce | Stručný popis |
---|---|---|
1 | first | získání prvních N prvků z pole |
2 | last | získání posledních N prvků z pole |
3 | initial | získání prvků z pole kromě posledních N prvků |
4 | rest | získání všech prvků z pole za indexem N |
Podívejme se nejprve na chování funkce first, která získá buď první prvek z pole (pokud N není zadáno) nebo prvních N prvků. Druhá část příkladu ukazuje použití funkce last:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- vstupní pole s = range(12) printSeparator() print("original array") printArray(s) -- funkce first printSeparator() print("first(s)") printArray(first(s)) -- funkce first s udáním počtu prvků printSeparator() print("first(s, 5)") printArray(first(s, 5)) -- funkce first s udáním nulového počtu prvků printSeparator() print("first(s, 0)") printArray(first(s, 0)) -- funkce last printSeparator() print("last(s)") printArray(last(s)) -- funkce last s udáním počtu prvků printSeparator() print("last(s, 5)") printArray(last(s, 5)) -- funkce last s udáním nulového počtu prvků printSeparator() print("last(s, 0)") printArray(last(s, 0))
Výsledky:
------------------------------- original array 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 ------------------------------- first(s) 1 1 ------------------------------- first(s, 5) 1 1 2 2 3 3 4 4 5 5 ------------------------------- first(s, 0) ------------------------------- last(s) 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 ------------------------------- last(s, 5) 1 8 2 9 3 10 4 11 5 12 ------------------------------- last(s, 0)
8. Získání části pole funkcemi initial a rest
Další dvě funkce zmíněné již v rámci předchozí kapitoly umožňují, aby se při přístupu k části pole nemusely používat (relativně složité) výpočty zahrnující délku pole (s běžnými problémy typu ±1). Operace prováděné těmito funkcemi jsou založeny na first a last, ovšem neuvádí se počet prvků, které se mají přečíst, ale relativní index od druhého konce pole. Opět si ukažme, jak se tyto operace používají:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArray(array) for index, value in ipairs(array) do print(index, value) end end -- oddělení obsahu function printSeparator() print("-------------------------------") end -- vstupní pole s = range(12) printSeparator() print("original array") printArray(s) -- funkce initial printSeparator() print("initial(s)") printArray(initial(s)) -- funkce initial s udáním počtu prvků printSeparator() print("initial(s, 5)") printArray(initial(s, 5)) -- funkce initial s udáním nulového počtu prvků printSeparator() print("initial(s, 0)") printArray(initial(s, 0)) -- funkce rest printSeparator() print("rest(s)") printArray(rest(s)) -- funkce rest s udáním počtu prvků printSeparator() print("rest(s, 5)") printArray(rest(s, 5)) -- funkce rest s udáním nulového počtu prvků printSeparator() print("rest(s, 0)") printArray(rest(s, 0))
Ze zobrazených výsledků je patrné rozdílné chování oproti funkcím first a last:
------------------------------- original array 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 ------------------------------- initial(s) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 ------------------------------- initial(s, 5) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 ------------------------------- initial(s, 0) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 ------------------------------- rest(s) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 ------------------------------- rest(s, 5) 1 5 2 6 3 7 4 8 5 9 6 10 7 11 8 12 ------------------------------- rest(s, 0) 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12
9. Pole využité jako množiny, množinové operace
Pole, speciálně pole s unikátními prvky, je možné využít i ve funkci množiny (množiny totiž nejsou v programovacím jazyce Lua základním datovým typem, na rozdíl od například Pythonu). Pro práci s množinami nabízí knihovna Moses několik funkcí:
# | Funkce | Význam |
---|---|---|
1 | union | sjednocení dvou či více množin |
2 | intersection | průnik dvou či více množin |
3 | difference | rozdíl množin |
4 | symmetricDifference | symetrická diference (negace průniku) |
Následuje ukázka použití všech čtyř zmíněných množinových operací:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a1 = {1, 2, 3, 4} a2 = {3, 4, 5, 6} printSeparator() print("a1") printArrayInLine(a1) printSeparator() print("a2") printArrayInLine(a2) printSeparator() print("union(a1, a2)") printArrayInLine(union(a1, a2)) printSeparator() print("intersection(a1, a2)") printArrayInLine(intersection(a1, a2)) printSeparator() print("difference(a1, a2)") printArrayInLine(difference(a1, a2)) printSeparator() print("difference(a2, a1)") printArrayInLine(difference(a2, a1)) printSeparator() print("symmetricDifference(a1, a2)") printArrayInLine(symmetricDifference(a1, a2)) printSeparator() print("symmetricDifference(a2, a1)") printArrayInLine(symmetricDifference(a2, a1))
Na výsledcích je vliv všech čtyř operací dobře patrný:
------------------------------- a1 1, 2, 3, 4 ------------------------------- a2 3, 4, 5, 6 ------------------------------- union(a1, a2) 1, 2, 3, 4, 5, 6 ------------------------------- intersection(a1, a2) 3, 4 ------------------------------- difference(a1, a2) 1, 2 ------------------------------- difference(a2, a1) 5, 6 ------------------------------- symmetricDifference(a1, a2) 1, 2, 5, 6 ------------------------------- symmetricDifference(a2, a1) 5, 6, 1, 2
10. Operace push a unshift
Další dvě funkce, které si dnes ve stručnosti popíšeme, se jmenují push a unshift. První funkce dokáže za konec pole připojit novou hodnotu. Dojde přitom k modifikaci původního pole – nejedná se tedy o operaci, kterou bychom v čistě funkcionální knihovně očekávali. Opakem funkce push je funkce nazvaná unshift, která naopak z pole poslední prvek odstraní a vrátí ho jako svoji návratovou hodnotu:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a = {} printSeparator() print("original array") printArrayInLine(a) printSeparator() print("after push('a')") push(a, "a") printArrayInLine(a) printSeparator() print("after push('b')") push(a, "b") printArrayInLine(a) printSeparator() print("after push('c')") push(a, "c") printArrayInLine(a) for i = 1, 5 do printSeparator() item = unshift(a) print("unshifted item:", item) print("after unshift()") printArrayInLine(a) end
Po spuštění tohoto příkladu je patrné, že skutečně dochází k modifikaci původního pole:
------------------------------- original array ------------------------------- after push('a') a ------------------------------- after push('b') a, b ------------------------------- after push('c') a, b, c ------------------------------- unshifted item: c after unshift() a, b ------------------------------- unshifted item: b after unshift() a ------------------------------- unshifted item: a after unshift() ------------------------------- unshifted item: nil after unshift() ------------------------------- unshifted item: nil after unshift()
11. Operace shift
Zatímco funkce unshift odstraňuje a vrací poslední prvek pole, provádí funkce shift odstranění a vrácení prvku prvního (což teoreticky znamená lineární časovou složitost). Opět si ukažme, jak se tato funkce může použít. Pole nejprve naplníme pomocí push a následně ho postupně vyprázdníme funkcí shift:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a = {} printSeparator() print("original array") printArrayInLine(a) printSeparator() print("after push('a')") push(a, "a") printArrayInLine(a) printSeparator() print("after push('b')") push(a, "b") printArrayInLine(a) printSeparator() print("after push('c')") push(a, "c") printArrayInLine(a) for i = 1, 5 do printSeparator() item = shift(a) print("shifted item:", item) print("after shift()") printArrayInLine(a) end
Výsledek po spuštění demonstračního příkladu:
------------------------------- original array ------------------------------- after push('a') a ------------------------------- after push('b') a, b ------------------------------- after push('c') a, b, c ------------------------------- shifted item: a after shift() b, c ------------------------------- shifted item: b after shift() c ------------------------------- shifted item: c after shift() ------------------------------- shifted item: nil after shift() ------------------------------- shifted item: nil after shift()
12. Operace pop
Operace nazvaná pop je pouze jmenným aliasem k výše popsané funkci shift, takže jen pro úplnost:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a = {} printSeparator() print("original array") printArrayInLine(a) printSeparator() print("after push('a')") push(a, "a") printArrayInLine(a) printSeparator() print("after push('b')") push(a, "b") printArrayInLine(a) printSeparator() print("after push('c')") push(a, "c") printArrayInLine(a) for i = 1, 5 do printSeparator() item = pop(a) print("poped item:", item) print("after pop()") printArrayInLine(a) end
Výsledky by měly být stejné jako v předchozím demonstračním příkladu:
------------------------------- original array ------------------------------- after push('a') a ------------------------------- after push('b') a, b ------------------------------- after push('c') a, b, c ------------------------------- poped item: a after pop() b, c ------------------------------- poped item: b after pop() c ------------------------------- poped item: c after pop() ------------------------------- poped item: nil after pop() ------------------------------- poped item: nil after pop()
13. Řez polem s využitím operace slice
Podobně jako range, first a last patří do běžného repertoáru knihoven pro práci se sekvencemi popř. s poli (seznamy) i funkce nazvaná slice. Ta provádí řez polem, tj. vrací prvky ležící mezi dvojicí indexů. Jednotlivé implementace se od sebe odlišují podle toho, zda je horní index chápán „včetně“ či „kromě“. V knihovně Moses jsou vráceny všechny prvky od prvního zadaného indexu do indexu druhého, a to včetně obou mezí.
Ukázka použití operace slice:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a = range(10) printSeparator() print("Original array") printArrayInLine(a) printSeparator() print("slice(a)") printArrayInLine(slice(a)) printSeparator() print("slice(a, 5)") printArrayInLine(slice(a, 5)) printSeparator() print("slice(a, 5, 5)") printArrayInLine(slice(a, 5, 5)) printSeparator() print("slice(a, 4, 8)") printArrayInLine(slice(a, 4, 8)) printSeparator() print("slice(a, 0, 100)") printArrayInLine(slice(a, 0, 100)) printSeparator() print("slice(a, 100, 0)") printArrayInLine(slice(a, 100, 0))
Z výsledků zobrazených pod tímto odstavcem je patrné, že pokud horní či dolní index přesahuje meze pole, použije se index 1 popř. index odpovídající délce pole (#pole):
------------------------------- Original array 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ------------------------------- slice(a) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ------------------------------- slice(a, 5) 5, 6, 7, 8, 9, 10 ------------------------------- slice(a, 5, 5) 5 ------------------------------- slice(a, 4, 8) 4, 5, 6, 7, 8 ------------------------------- slice(a, 0, 100) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ------------------------------- slice(a, 100, 0)
14. Získání unikátních prvků v poli
Další potenciálně velmi užitečnou operací je získání unikátních prvků v poli, tj. přečtení nového pole, v němž se každá hodnota vyskytuje maximálně jedenkrát. Právě díky této operaci lze s poli pracovat stejně jako s množinami. Prvky v poli přitom nemusí být nijak uspořádány, což je ostatně patrné i z následujícího demonstračního příkladu:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("-------------------------------") end a = range(10) printSeparator() print("Original array") printArrayInLine(a) print("unique(a)") printArrayInLine(unique(a)) a = {1, 2, 3, 1, 2, 3} printSeparator() print("Original array") printArrayInLine(a) print("unique(a)") printArrayInLine(unique(a)) a = {3, 2, 1, 1, 2, 3} printSeparator() print("Original array") printArrayInLine(a) print("unique(a)") printArrayInLine(unique(a))
Povšimněte si, jakým způsobem jsou uspořádány prvky ve výsledném poli. Z tohoto uspořádání lze vyčíst, jak vlastně pracuje algoritmus, nad nímž je funkce unique postavena:
------------------------------- Original array 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 unique(a) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ------------------------------- Original array 1, 2, 3, 1, 2, 3 unique(a) 1, 2, 3 ------------------------------- Original array 3, 2, 1, 1, 2, 3 unique(a) 3, 2, 1
15. Výběr prvků ze začátku pole funkcí vyššího řádu selectWhile
Z polí je možné získat začátek či naopak zbytek pole s využitím funkcí nazvaných selectWhile a dropWhile. Těmto funkcím je zapotřebí ve druhém parametru předat takzvaný predikát určující, zda prvek splňuje nějakou podmínku (ovšem pozor – chování je odlišné od funkce filter popsané v sedmnácté kapitole). V případě druhého parametru předávaného do selectWhile a dropWhile se jedná o běžnou funkci popř. o funkci anonymní, která by měla akceptovat jeden parametr (hodnotu prvku ze sekvence) a vracet by měla pravdivostní hodnotu true či false popř. nil, který má v kontextu pravdivostních hodnot stejný význam jako true.
Rozdíly oproti funkcím z knihovny Lua Fun jsou shrnuty v tabulce:
# | Funkce z Lua Fun | Funkce z Moses | Stručný popis |
---|---|---|---|
1 | take_while(predikát, sekvence) | selectWhile(pole, predikát) | získání prvků ze začátku sekvence na základě zadané podmínky |
2 | drop_while(predikát, sekvence) | dropWhile(pole, predikát) | získání nové sekvence získané přeskočením prvků na začátku základě podmínky |
V dalším demonstračním příkladu si ukážeme základní chování funkce vyššího řádu selectWhile:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("--------------------------------------------") end a = range(10) printSeparator() print("Original array") printArrayInLine(a) printSeparator() print("selectWhile(a, function (x) return x<=5 end)") printArrayInLine(selectWhile(a, function (x) return x<=5 end)) printSeparator() print("selectWhile(a, function (x) return x%2 == 1 end)") printArrayInLine(selectWhile(a, function (x) return x%2 == 1 end)) printSeparator() print("selectWhile(a, function (x) return true end)") printArrayInLine(selectWhile(a, function (x) return true end)) printSeparator() print("selectWhile(a, function (x) return false end)") printArrayInLine(selectWhile(a, function (x) return false end))
Výsledky získané po spuštění ukazují, jak se tato funkce chová:
-------------------------------------------- Original array 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- selectWhile(a, function (x) return x<=5 end) 1, 2, 3, 4, 5 -------------------------------------------- selectWhile(a, function (x) return x%2 == 1 end) 1 -------------------------------------------- selectWhile(a, function (x) return true end) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- selectWhile(a, function (x) return false end)
16. Přeskočení prvků ze začátku pole funkcí vyššího řádu dropWhile
Logickým opakem funkce selectWhile z předchozí kapitoly je funkce nazvaná dropWhile, která dokáže na základě hodnoty vracené z predikátu (typicky z anonymní funkce) přeskočit prvky na začátku sekvence. Až na opačné pořadí parametrů se tato funkce chová podobně jako prakticky stejně pojmenovaná funkce drop_while z knihovny Lua Fun, takže se ihned podívejme na demonstrační příklad:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("--------------------------------------------") end a = range(10) printSeparator() print("Original array") printArrayInLine(a) printSeparator() print("dropWhile(a, function (x) return x<=5 end)") printArrayInLine(dropWhile(a, function (x) return x<=5 end)) printSeparator() print("dropWhile(a, function (x) return x%2 == 1 end)") printArrayInLine(dropWhile(a, function (x) return x%2 == 1 end)) printSeparator() print("dropWhile(a, function (x) return true end)") printArrayInLine(dropWhile(a, function (x) return true end)) printSeparator() print("dropWhile(a, function (x) return false end)") printArrayInLine(dropWhile(a, function (x) return false end))
Z vytištěných zpráv je patrné, že je skutečně možné přeskočit prvky na začátku pole (první výsledek), popř. dokonce získat prázdné pole (předposlední výsledek) či pole odpovídající poli původnímu (výsledek poslední):
-------------------------------------------- Original array 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- dropWhile(a, function (x) return x<=5 end) 6, 7, 8, 9, 10 -------------------------------------------- dropWhile(a, function (x) return x%2 == 1 end) 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- dropWhile(a, function (x) return true end) -------------------------------------------- dropWhile(a, function (x) return false end) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
17. Výběr prvků z pole s využitím funkce vyššího řádu filter
Poslední funkcí, kterou si v dnešním článku popíšeme, je funkce nazvaná filter. I s touto funkcí jsme se seznámili minule při popisu knihovny Lua Fun, takže si jen v krátkosti shrňme její základní vlastnosti. Tato funkce postupně prochází všemi prvky pole a pro každý takto získaný prvek (resp. přesněji řečeno pro jeho hodnotu) volá nějakou programátorem zvolenou funkci – takzvaný predikát. V případě, že tato funkce vrátí pravdivostní hodnotu true je prvek vložen do nového pole, které je výsledkem funkce filter. Pokud naopak funkce/predikát vrátí hodnotu false nebo nil, je takový prvek ignorován. Kvůli tomu, že do funkce filter předáváme jinou funkci, je filter funkcí vyššího řádu. Ukažme si příklad použití:
-- načtení knihovny Moses a současně import symbolů do globálního jmenného prostoru M = require "moses" M.import() -- tisk obsahu pole function printArrayInLine(array) for i, value in ipairs(array) do io.write(value) if i ~= #array then io.write(", ") end end print() end -- oddělení obsahu function printSeparator() print("--------------------------------------------") end a = range(10) printSeparator() print("Original array") printArrayInLine(a) printSeparator() print("filter(a, function (x) return x<=5 end)") printArrayInLine(filter(a, function (x) return x<=5 end)) printSeparator() print("filter(a, function (x) return x%2 == 1 end)") printArrayInLine(filter(a, function (x) return x%2 == 1 end)) printSeparator() print("filter(a, function (x) return true end)") printArrayInLine(filter(a, function (x) return true end)) printSeparator() print("filter(a, function (x) return false end)") printArrayInLine(filter(a, function (x) return false end))
Výsledky získané po spuštění tohoto demonstračního příkladu:
-------------------------------------------- Original array 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- filter(a, function (x) return x<=5 end) 1, 2, 3, 4, 5 -------------------------------------------- filter(a, function (x) return x%2 == 1 end) 1, 3, 5, 7, 9 -------------------------------------------- filter(a, function (x) return true end) 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 -------------------------------------------- filter(a, function (x) return false end)
18. Repositář s demonstračními příklady
Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do nového Git repositáře, který je dostupný na adrese https://github.com/tisnik/functional-lua. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má přibližně několik jednotek kilobajtů), můžete namísto toho použít odkazy na jednotlivé demonstrační příklady a jejich části, které naleznete v následující tabulce:
19. Články o programovacím jazyce Lua i o technologii LuaJITu
Předchozí dva články o funkcionálním stylu programování podporovaného knihovnou Lua Fun:
- Lua Fun: knihovna pro zpracování konečných i nekonečných sekvencí v jazyce Lua
https://www.root.cz/clanky/lua-fun-knihovna-pro-zpracovani-konecnych-i-nekonecnych-sekvenci-v-jazyce-lua/ - Lua Fun: knihovna pro zpracování konečných i nekonečných sekvencí v jazyce Lua (dokončení)
https://www.root.cz/clanky/lua-fun-knihovna-pro-zpracovani-konecnych-i-nekonecnych-sekvenci-v-jazyce-lua-dokonceni/
Programovacím jazykem Lua jsme se již na stránkách Rootu poměrně podrobně zabývali v samostatném seriálu. Jedná se o snadno naučitelný jazyk, který je ovšem (mj. i díky konceptu metatabulek) rozšiřitelný a poměrně tvárný. Viz též následující odkazy na již vydané články (včetně odkazu na e-book, jenž na základě těchto článků později vznikl):
- Programovací jazyk Lua
https://www.root.cz/clanky/programovaci-jazyk-lua/ - Základní konstrukce v programovacím jazyku Lua
https://www.root.cz/clanky/zakladni-konstrukce-v-programovacim-jazyku-lua/ - Operátory a asociativní pole v jazyku Lua
https://www.root.cz/clanky/operatory-a-asociativni-pole-v-jazyku-lua/ - Funkce v programovacím jazyku Lua
https://www.root.cz/clanky/funkce-v-programovacim-jazyku-lua/ - Funkce v programovacím jazyku Lua – uzávěry
https://www.root.cz/clanky/funkce-v-programovacim-jazyku-lua-uzavery/ - Programovací jazyk Lua vestavěný do aplikací
https://www.root.cz/clanky/programovaci-jazyk-lua-vestaveny-do-aplikaci/ - Programovací jazyk Lua v aplikacích II
https://www.root.cz/clanky/programovaci-jazyk-lua-v-aplikacich-ii/ - Objektově orientované programování v Lua
https://www.root.cz/clanky/objektove-orientovane-programovani-v-lua/ - Objektově orientované programování v Lua II
https://www.root.cz/clanky/objektove-orientovane-programovani-v-lua-ii/ - Programovací jazyk Lua a koprogramy
https://www.root.cz/clanky/programovaci-jazyk-lua-a-koprogramy/ - Knihovny a frameworky pro programovací jazyk Lua
https://www.root.cz/clanky/knihovny-a-frameworky-pro-programovaci-jazyk-lua/ - Lua + LÖVE: vytvořte si vlastní hru
https://www.root.cz/clanky/lua-love-vytvorte-si-vlastni-hru/ - Hrátky se systémem LÖVE
https://www.root.cz/clanky/hratky-se-systemem-love/ - Vytváříme hru v systému LÖVE
https://www.root.cz/clanky/vytvarime-hru-v-systemu-love/ - Hrátky se systémem LÖVE – částicové systémy
https://www.root.cz/clanky/hratky-se-systemem-love-casticove-systemy/ - Hrátky se systémem LÖVE – kolize a odrazy těles
https://www.root.cz/clanky/hratky-se-systemem-love-ndash-kolize-a-odrazy-teles/ - Hrátky se systémem LÖVE – kolize a odrazy těles II
https://www.root.cz/clanky/hratky-se-systemem-love-kolize-a-odrazy-teles-ii/ - Hrátky se systémem LÖVE – pružné vazby mezi tělesy
https://www.root.cz/clanky/hratky-se-systemem-love-pruzne-vazby-mezi-telesy/ - Hrátky se systémem LÖVE – dokončení
https://www.root.cz/clanky/hratky-se-systemem-love-dokonceni/ - LuaJ – implementace jazyka Lua v Javě
https://www.root.cz/clanky/luaj-ndash-implementace-jazyka-lua-v-jave/ - LuaJ a skriptování podle specifikace JSR-223
https://www.root.cz/clanky/luaj-a-skriptovani-podle-specifikace-jsr-223/ - Metalua: programovatelné rozšíření sémantiky jazyka Lua
https://www.root.cz/clanky/metalua-programovatelne-rozsireni-semantiky-jazyka-lua/ - Metalua: užitečná rozšíření jazyka Lua
https://www.root.cz/clanky/metalua-uzitecna-rozsireni-jazyka-lua/ - Programovací jazyk Lua v roli skriptovacího jazyka pro WWW stránky
https://www.root.cz/clanky/programovaci-jazyk-lua-v-roli-skriptovaciho-jazyka-pro-www-stranky/ - Interpretry, překladače, JIT překladače a transpřekladače programovacího jazyka Lua
https://www.root.cz/clanky/interpretry-prekladace-jit-prekladace-a-transprekladace-programovaciho-jazyka-lua/ - Kooperace mezi jazykem Lua a nativním (céčkovým) kódem
https://www.root.cz/clanky/kooperace-mezi-jazykem-lua-a-nativnim-ceckovym-kodem/ - Kooperace mezi jazykem Lua a nativním (céčkovým) kódem: knihovna FFI
https://www.root.cz/clanky/kooperace-mezi-jazykem-lua-a-nativnim-ceckovym-kodem-knihovna-ffi/ - Profilery pro programovací jazyk Lua
https://www.root.cz/clanky/profilery-pro-programovaci-jazyk-lua/ - Využití knihovny debug v programovacím jazyku Lua
https://www.root.cz/clanky/vyuziti-knihovny-debug-v-programovacim-jazyku-lua/ - Programovací jazyk Lua (e-book)
https://www.knihydobrovsky.cz/e-kniha/programovaci-jazyk-lua-240253190
Původně byla Lua realizována jako klasický interpret – prováděl se automatický a prakticky okamžitý překlad do bajtkódu, který byl následně interpretován. Později byl vytvořen i plnohodnotný (a nutno podotknout, že až neobvykle dobrý) just-in-time (JIT) překladač nazvaný LuaJIT. Touto zajímavou technologií jsme se zabývali v následující sérii článků (které jsou poněkud paradoxně součástí seriálu o programovacím jazyku Java a JVM):
- LuaJIT – Just in Time překladač pro programovací jazyk Lua
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (2)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-2/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (3)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-3/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (4)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-4/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (5 – tabulky a pole)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-5-tabulky-a-pole/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (6 – překlad programových smyček do mezijazyka LuaJITu)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-6-preklad-programovych-smycek-do-mezijazyka-luajitu/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (7 – dokončení popisu mezijazyka LuaJITu)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-7-dokonceni-popisu-mezijazyka-luajitu/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (8 – základní vlastnosti trasovacího JITu)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-8-zakladni-vlastnosti-trasovaciho-jitu/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (9 – další vlastnosti trasovacího JITu)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-9-dalsi-vlastnosti-trasovaciho-jitu/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (10 – JIT překlad do nativního kódu)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-10-jit-preklad-do-nativniho-kodu/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (11 – JIT překlad do nativního kódu procesorů s architekturami x86 a ARM)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-11-jit-preklad-do-nativniho-kodu-procesoru-s-architekturami-x86-a-arm/ - LuaJIT – Just in Time překladač pro programovací jazyk Lua (12 – překlad operací s reálnými čísly)
https://www.root.cz/clanky/luajit-just-in-time-prekladac-pro-programovaci-jazyk-lua-12-preklad-operaci-s-realnymi-cisly/
A konečně nesmíme zapomenout na to, že kromě původní implementace interpretru a LuaJITu existuje celá řada dalších implementací tohoto programovacího jazyka. Některé z těchto implementací byly zmíněny v následujících článcích:
- Skriptovací jazyk Lua v aplikacích naprogramovaných v Go
https://www.root.cz/clanky/skriptovaci-jazyk-lua-v-aplikacich-naprogramovanych-v-go/ - Programovací jazyk Lua v roli skriptovacího jazyka pro WWW stránky
https://www.root.cz/clanky/programovaci-jazyk-lua-v-roli-skriptovaciho-jazyka-pro-www-stranky/ - LuaJ – implementace jazyka Lua v Javě
https://www.root.cz/clanky/luaj-ndash-implementace-jazyka-lua-v-jave/ - Tvorba pluginů pro Vim s využitím programovacího jazyka Lua
https://www.root.cz/clanky/tvorba-pluginu-pro-vim-s-vyuzitim-programovaciho-jazyka-lua/
20. Odkazy na Internetu
- Repositář projektu Lua Fun
https://github.com/luafun/luafun - Lua Functional 0.1.3 documentation
https://luafun.github.io/reference.html - Getting Started
https://luafun.github.io/getting_started.html - Rockspec knihovny Fun
https://raw.githubusercontent.com/luafun/luafun/master/fun-scm-1.rockspec - Awesome Lua – A curated list of quality Lua packages and resources.
https://github.com/LewisJEllis/awesome-lua - Repositář projektu Moses
https://github.com/Yonaba/Moses/ - Lambda the Ultimate: Coroutines in Lua
http://lambda-the-ultimate.org/node/438 - Coroutines Tutorial
http://lua-users.org/wiki/CoroutinesTutorial - Lua Coroutines Versus Python Generators
http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators - Programming in Lua 9.1 – Coroutine Basics
http://www.lua.org/pil/9.1.html - Wikipedia CZ: Koprogram
http://cs.wikipedia.org/wiki/Koprogram - Wikipedia EN: Coroutine
http://en.wikipedia.org/wiki/Coroutine - Repositář knihovny Moses
https://github.com/Yonaba/Moses/ - Návod k použití knihovny Moses
https://github.com/Yonaba/Moses/blob/master/doc/tutorial.md - How to understand clojure's lazy-seq
https://stackoverflow.com/questions/44095400/how-to-understand-clojures-lazy-seq - Lua Implementations
http://lua-users.org/wiki/LuaImplementations - Generator (computer programming)
https://en.wikipedia.org/wiki/Generator_(computer_programming) - Lambda the Ultimate: Coroutines in Lua,
http://lambda-the-ultimate.org/node/438 - Coroutines Tutorial,
http://lua-users.org/wiki/CoroutinesTutorial - Lua Coroutines Versus Python Generators,
http://lua-users.org/wiki/LuaCoroutinesVersusPythonGenerators - Category:Lua na Rosetta code
https://rosettacode.org/wiki/Category:Lua - Programming in Lua: 23 – The Debug Library
http://www.lua.org/pil/23.html - Programming in Lua: 23.1 – Introspective Facilities
http://www.lua.org/pil/23.1.html - Programming in Lua: 23.2 – Hooks
http://www.lua.org/pil/23.2.html - Lua 5.2 Reference Manual: 6.10 – The Debug Library
http://www.lua.org/manual/5.2/manual.html#6.10 - Turtles all the way down
https://en.wikipedia.org/wiki/Turtles_all_the_way_down - Issues k projektu LuaFun
https://github.com/luafun/luafun/issues - Archived | Embed Lua for scriptable apps
https://developer.ibm.com/tutorials/l-embed-lua/ - Embedding Lua
https://www.oreilly.com/library/view/lua-quick-start/9781789343229/3a6f3daf-f74c-4a25-a125–584da58568e4.xhtml