Obsah
1. Seznamy v roli základního strukturovaného datového typu všech LISPovských jazyků
2. Základní funkce pro zpracování seznamů
3. Průchod všemi prvky seznamu s využitím funkce for/list
7. Funkce vyššího řádu foldl a foldr
9. Funkce a makra používaná pro zpracování vektorů
11. Funkce a makra používaná pro práci s hešovacími tabulkami
12. Generátor číselné řady (typu range)
13. Specializované datové typy
14. Celočíselné numerické hodnoty s pevným počtem bitů (fixnum)
18. Repositář s demonstračními příklady
1. Seznamy v roli základního strukturovaného datového typu všech LISPovských jazyků
Nejdříve se zaměříme na funkce a makra používaná pro zpracování různých datových struktur podporovaných programovacím jazykem Racket. Podobně, jako je tomu v prakticky jakémkoli jiném lispovském programovacím jazyku, je základním strukturovaným datovým typem seznam (list), na který se taktéž můžeme dívat jako na vzájemně provázané tečka-dvojice (ostatně samotný název LIST vznikl z dvousloví „LISt Processor“). Nejprve si připomeňme, jakým způsobem je vlastně možné seznam vytvořit. V případě, že máme k dispozici konkrétní prvky, které se mají do seznamu vložit, použijeme konstruktor list, popř. můžeme seznam reprezentovat přímo zápisem jeho prvků do závorek.
Prázdný seznam:
(list) '() empty '()
Seznam celých čísel:
(list 1 2 3 4) '(1 2 3 4)
Seznam řetězců:
(list "www" "root" "cz") '("www" "root" "cz")
Seznam symbolů:
(list '#:foo '#:bar '#:baz) '(#:foo #:bar #:baz)
Vnořený seznam:
(list (list 1 2) (list 3 4) (list 5 (list 6))) '((1 2) (3 4) (5 (6)))
Seznam lze napsat i přímo ve formě prvků umístěných do závorek, ovšem nesmíme zapomenout na použití speciální formy quote, aby se interpret nesnažil o vyhodnocení seznamu (jako funkce):
(quote (1 2 3 4)) (quote "www" "root" "cz")
Speciální forma quote se v praxi používá tak často, že je umožněno ji zkrátit a zapisovat pomocí apostrofu:
'(1 2 3 4) '(1 2 3 4) '("www" "root" "cz") '("www" "root" "cz")
Jak se tedy liší použití konstruktoru list od přímého zapsání seznamu s quote? V prvním případě mohou být prvky seznamy vyhodnoceny (vypočítány), ve druhém případě nikoli:
(list (+ 1 2) (+ 3 4)) '(3 7) (quote ((+ 1 2) (+ 3 4))) '((+ 1 2) (+ 3 4))
2. Základní funkce pro zpracování seznamů
V knihovnách programovacího jazyka Racket je k dispozici poměrně velké množství funkcí určených pro práci se seznamy. Mnohé z těchto funkcí bylo převzato ze starších dialektů jazyka LISP, popř. přímo z programovacího jazyka Scheme, další funkce pak nalezneme v balíčku racket/list. Některé z těchto funkcí si ukážeme na (velmi jednoduchých) demonstračních příkladech.
Zjištění délky seznamu, tj. počtu prvků v seznamu:
(define x '(1 2 3)) (length x) 3 (define z '()) (length z) 0
Výběr n-tého prvku ze seznamu (i s případnou chybou, pokud index nespadá do očekávaného rozsahu):
(list-ref x 2) 3 (list-ref x 4) ; list-ref: index too large for list ; index: 4 ; in: '(1 2 3) ; [,bt for context]
Výběr prvního prvku ze seznamu:
(first x) 1
(car x) 1
Vrácení zbytku seznamu bez prvního prvku:
(rest x) '(2 3)
(cdr x) '(2 3)
Test, zda seznam obsahuje daný prvek či nikoli:
(member 2 x) '(2 3) (member 3 x) '(3) (member 1 x) '(1 2 3) (member 4 x) #f
Otočení prvků v seznamu:
(reverse x) '(3 2 1)
Vložení nového prvku do seznamu na jeho začátek (což je jediná operace, kterou lze provést v konstantním čase):
(cons 4 x) '(4 1 2 3) (cons 4 z) '(4)
Vytvoření seznamů z tečka dvojic:
(cons 1 empty) '(1) (cons 1 (cons 2 empty)) '(1 2) (cons 1 (cons 2 (cons 3 empty))) '(1 2 3)
Chování funkce cons se odlišuje podle toho, jakého typu jsou parametry této funkci předané. Běžného chování známého z jiných jazyků dosáhneme tehdy, pokud funkci předáme dva atomy. Výsledkem v tomto případě bude tečka-dvojice:
(cons 1 2) '(1 . 2) (cons 1 (cons 2 3)) '(1 2 . 3) (cons (cons 1 2) (cons 3 4)) '((1 . 2) 3 . 4)
Spojení dvou či více seznamů:
(append x x) '(1 2 3 1 2 3) (append x x (list 9 9 9)) '(1 2 3 1 2 3 9 9 9) (append '(0 0 0) x x (list 9 9 9)) '(0 0 0 1 2 3 1 2 3 9 9 9)
K dipozici je i predikát pro zjištění, zda je zkoumaná hodnota seznamem či nikoli:
(define x '(1 2 3)) (list? x) #t (define y 123) (list? y) #f (define z '()) (list? z) #t
3. Průchod všemi prvky seznamu s využitím funkce for/list
Pro průchod všemi prvky seznamu můžeme použít funkci nazvanou příznačně for/list (připomeňme si, že v Racketu nepatří lomítko mezi specializované znaky a tudíž se může objevit i ve jméně funkce). Použití je triviální:
(for/list ((item (list 1 2 3 4 5))) (+ item item)) '(2 4 6 8 10)
Rozepsání na více řádků a použití znaků [] namísto () pro větší čitelnost:
(for/list ([item (list 1 2 3 4 5)]) (+ item item)) '(2 4 6 8 10)
Průchod dvěma seznamy:
(for/list ([i1 (list 1 2 3 4)] [i2 (list 6 7 8 9)]) (+ i1 i2)) '(7 9 11 13)
Pokud je jeden ze seznamů kratší, zkrátí se i počet průchodů smyčkou:
(for/list ([i1 (list 1 2 3 4)] [i2 (list 6 7 8 9 10)]) (+ i1 i2)) '(7 9 11 13) (for/list ([i1 (list 1 2 3 4 5)] [i2 (list 6 7 8 9)]) (+ i1 i2)) '(7 9 11 13)
V navazující kapitole popsanou funkci map je možné naprogramovat právě s využitím for/list, a to například následujícím způsobem:
(define (map-function fce lst) (for/list ([item lst]) (fce item)))
4. Funkce vyššího řádu map
Zatímco v běžných imperativních programovacích jazycích se seznamy zpracovávají prvek po prvku s využitím nějaké formy programové smyčky, v jazyku Racket se setkáme spíše s použitím několika funkcí vyššího řádu, které jako svůj vstup akceptují seznam a nějakou funkci, která je postupně aplikována buď na prvky seznamu, nebo na prvek seznamu a akumulátor, jehož hodnota se postupně při zpracovávání jednotlivých prvků seznamu mění. Výsledkem bývá buď nový seznam, nebo výsledná hodnota akumulátoru. Tyto funkce se většinou nazývají map, filter a reduce či fold a v Racketu existuje hned několik variant od každé této funkce.
První varianta funkce map se jmenuje … map. Tato funkce vyššího řádu akceptuje (v prvním parametru) funkci s jedním vstupním parametrem, která bude aplikována na prvky seznamu, který musí být do map předán jako druhý parametr. Pochopitelně se podíváme na demonstrační příklady, protože se s funkcí map v praxi setkáme velmi často.
Aplikace existující funkce na seznam, výsledkem bude jiný seznam:
(map sqrt (list 1 4 9 16 25)) '(1 2 3 4 5)
Výsledný seznam může obsahovat i prvky odlišného typu:
(map even? (list 1 4 9 16 25)) '(#f #t #f #t #f) (map string-length (list "www" "." "root" "." "cz")) '(3 1 4 1 2)
V případě, že budeme chtít na prvky seznamu aplikovat vlastní funkci (s jedním vstupem), máme dvě možnosti:
- Vytvořit pojmenovanou funkci a tu následně do map předat
- Přímo ve funkci map deklarovat funkci anonymní, která bude omezena právě na ono jediné volání funkce map
Opět si pochopitelně oba dva zmíněné případy ukážeme prakticky. Budeme chtít, aby se hodnoty všech prvků seznamu zdvojnásobily. Pochopitelně je snadné si vytvořit novou funkci pojmenovanou například double a tu následně pro tento účel použít:
(define (double x) (+ x x)) (map double (list 1 2 3 4 5)) '(2 4 6 8 10)
Alternativně můžeme podobnou funkcionalitu implementovat jako funkci anonymní na jediném řádku:
(map (lambda (x) (+ x x)) (list 1 2 3 4 5)) '(2 4 6 8 10)
Vzhledem k tomu, že výsledkem funkce map je opět seznam, lze volání vnořit, i když to nemusí být příliš čitelné:
(map (lambda (x) (/ 1 x)) (map (lambda (x) (+ x x)) (list 1 2 3 4 5))) '(1/2 1/4 1/6 1/8 1/10)
Nebo:
(define (inc x) (+ 1 x)) (inc 3) 4 (map inc (map (lambda (x) (/ 1 x)) (map (lambda (x) (+ x x)) (list 1 2 3 4 5)))) '(3/2 5/4 7/6 9/8 11/10)
5. Další varianty funkce map
Ve skutečnosti existují v programovacím jazyce Racket, resp. přesněji řečeno v jeho základních knihovnách, i další varianty funkce map. Poměrně často potřebujeme zjistit, zda prvky seznamu odpovídají nějaké podmínce. Podmínku lze zapsat s využitím klasického predikátu, tj. funkce s jedním vstupním parametrem, která vrací pravdivostní hodnotu #t nebo #f. Pokud použijeme funkci vyššího řádu map s takovým predikátem, bude výsledkem nový seznam obsahující pouze pravdivostní hodnoty.
Pokud například budeme chtít zjistit, které prvky jsou sudé, můžeme postupovat takto:
(map even? (list 1 4 9 16 25)) '(#f #t #f #t #f)
Často však potřebujeme zjistit, jestli všechny prvky odpovídají zadané podmínce (predikátu), zda žádný prvek predikátu neodpovídá, nebo dokonce zda alespoň nějaký (tedy minimálně jeden) prvek predikátu odpovídá. Budeme tedy chtít výsledný vektor nějakým způsobem konsolidovat do jediné pravdivostní hodnoty #t nebo #f. A právě pro tento účel slouží další varianty funkce map nazvané příznačně andmap a ormap. Na následujících řádcích je ukázáno, jak se tyto varianty chovají při zpracování vstupních seznamů.
Je alespoň jeden prvek sudý?
(ormap even? (list 1 4 9 16 25)) #t (ormap even? (list 1 3 5)) #f
Jsou všechny prvky seznamu sudé?
(andmap even? (list 1 4 9 16 25)) #f (andmap even? (list 2 4 6)) #t
Chování u prázdného seznamu může být poněkud překvapující, ovšem je konzistentní se sémantikou prováděných operací:
(map even? empty) '() (andmap even? empty) #t (ormap even? empty) #f
6. Funkce vyššího řádu filter
Funkci map zmíněnou v předchozích kapitolách pravděpodobně mnoho čtenářů již zná z dalších programovacích jazyků. Týká se to i funkce nazvané filter, která dnes již patří k základní nabídce funkcí i v mainstreamových programovacích jazycích (kde bývá zobecněna pro zpracování libovolných streamů či sekvencí). I tato funkce je funkcí vyššího řádu, a to z toho důvodu, že jako svůj vstup akceptuje jinou funkci. Zde se konkrétně musí jednat o predikát, tedy o funkci vracející pro každý svůj vstup pravdivostní hodnotu #t nebo #f. Na základě výsledné hodnoty predikátu se právě zpracovávaný prvek buď objeví ve výstupním seznamu či nikoli – tato funkce tedy obecně vrací seznam, ale s odlišným počtem prvků, než kolik jich má seznam vstupní (pokud není predikát splněn pro žádný prvek ze vstupního seznamu, bude výsledkem prázdný seznam).
Opět se podívejme na několik demonstračních příkladů (s několika jsme se již setkali v předchozích částech tohoto seriálu při popisu ostatních dialektů programovacího jazyka Scheme):
(filter even? (list 1 2 3 4 5 6 7)) '(2 4 6) (filter odd? (list 1 2 3 4 5 6 7)) '(1 3 5 7) (filter positive? (list 1 2 3 4 5 6 7)) '(1 2 3 4 5 6 7) (filter negative? (list 1 2 3 4 5 6 7)) '()
Můžeme si samozřejmě vytvořit i vlastní predikát a ten následně použít:
(define (not-dot s) (not (eq? s "."))) (filter not-dot (list "www" "." "root" "." "cz")) '("www" "root" "cz")
Použití anonymní funkce:
(filter (lambda (s) (not (eq? s "."))) (list "www" "." "root" "." "cz")) '("www" "root" "cz")
Čitelnější varianta:
(filter (lambda (s) (not (eq? s "."))) (list "www" "." "root" "." "cz")) '("www" "root" "cz")
7. Funkce vyššího řádu foldl a foldr
Ve většině programovacích jazyků inspirovaných funkcionálním programováním se kromě funkcí typu map a filter setkáme i s funkcí vyššího řádu, která se nazývá buď reduce nebo fold. Programovací jazyk Racket pochopitelně není výjimkou, takže i v něm nalezneme tento typ funkce, a to dokonce v několika variantách. Základní funkcí tohoto typu je funkce nazvaná foldl, která postupně zpracovává všechny prvky seznamu zleva doprava a aplikuje na každý prvek a akumulovanou hodnotu nějakou funkci. Výsledkem je v každé iteraci nová hodnota akumulátoru a po projití celého seznamu je výsledná hodnota uložená v akumulátoru současně i návratovou hodnotou funkce foldl. Samotné volání této funkce je ovšem nepatrně složitější, než tomu bylo u map a filter. Je tomu tak z toho důvodu, že kromě zpracovávající funkce (se dvěma parametry) a vstupního seznamu musíme funkci foldl předat i počáteční hodnotu akumulátoru.
Opět si ukážeme několik demonstračních příkladů.
Součet hodnot v seznamu a součet s počáteční hodnotou akumulátoru nastavenou na 100:
(foldl + 0 (list 1 2 3 4 5)) 15 (foldl + 100 (list 1 2 3 4 5)) 115
Postupná konstrukce seznamu z tečka-dvojic:
(foldl cons empty (list 1 2 3 4 5)) '(5 4 3 2 1)
Použití funkce foldr, která seznam zpracovává od posledního prvku:
(foldl cons empty (list 1 2 3 4 5)) '(1 2 3 4 5)
Při některých výpočtech je výsledek volání foldl a foldr totožný, ovšem foldl je paměťově efektivnější:
(foldr + 0 (list 1 2 3 4 5)) 15 (foldr + 100 (list 1 2 3 4 5)) 115
8. Vektory
Výše popsané seznamy jsou v lispovských programovacích jazycích základním strukturovaným datovým typem. Interně se jedná, jak již víme z předchozích částí tohoto seriálu, o lineárně vázané prvky, přičemž každý prvek je představován tečka dvojicí. V první části tečka-dvojice je uložena hodnota prvku, v části druhé pak reference na další prvek. Toto uspořádání je sice flexibilní a umožňuje snadnou tvorbu nového seznamu ze seznamu původního (cons, append), ovšem nevýhodou je pomalý přístup k jednotlivým prvkům, který je proveden v lineárním čase; tj. časová složitost je O(n). V případě, že je zapotřebí zajistit konstantní přístup k jednotlivým prvkům na základě jejich indexu, budeme s velkou pravděpodobností preferovat strukturovaný datový typ, který se bude chovat podobně jako pole v jiných programovacích jazycích. Takovým datovým typem je v jazyku Racket typ nazvaný příznačně vektor (vector).
Literál vektoru se zapisuje:
#(jednotlivé prvky vektoru)
Příklad:
#(1 2 3 4) '#(1 2 3 4) #() '#()
Konstruktorem vektorů je funkce vektor:
(vector 1 2 3 4) '#(1 2 3 4) (vector) '#()
Vektor může obsahovat prvky libovolného typu:
(vector (list 1 2 3 4) (vector 1 2 3 4)) '#((1 2 3 4) #(1 2 3 4)) (vector "foo" (list 1 2 3 4) "bar" (vector 1 2 3 4) "baz") '#("foo" (1 2 3 4) "bar" #(1 2 3 4) "baz")
Takto vytvořený vektor je měnitelný (mutable).
Vytvořit můžeme i vektor o zadané kapacitě prvků:
(make-vector 10) '#(0 0 0 0 0 0 0 0 0 0)
Takový vektor lze i inicializovat:
(make-vector 10 1/2) '#(1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2 1/2)
K dispozici je i predikát testující, zda je hodnota typu vektor či nikoli:
(vector? x) #f (vector? y) #t (vector? (vector)) #t
9. Funkce a makra používaná pro zpracování vektorů
V základní knihovně programovacího jazyka Racket je k dispozici několik desítek funkcí určených pro práci s vektory. Další funkce nalezneme v rozšiřující knihovně nazvané racket/vector, kterou je ovšem ve vytvářených skriptech potřeba explicitně načíst příkazem:
(require racket/vector)
Použití těchto funkcí si opět ukážeme na příkladech.
Vektory, s nimiž budeme pracovat:
(define v1 (vector 1 2 3 4)) (define v3 (vector)) (vector-length v3)
Délka vektorů (počet prvků):
(vector-length v1) 4 (vector-length v2) 4 (vector-length v3) 0
Přístup k prvkům vektorů (čtení) s případným nahlášením chyb:
(vector-ref v1 0) 1 (vector-ref v1 2) 3 (vector-ref v1 10) ; vector-ref: index is out of range ; index: 10 ; valid range: [0, 3] ; vector: '#(1 2 3 4) ; [,bt for context]
Nastavení nové hodnoty měnitelného vektoru, opět s případným hlášením chyby:
(vector-set! v1 2 -5) v1 '#(1 2 -5 4) (vector-set! v1 10 -5) ; vector-set!: index is out of range ; index: 10 ; valid range: [0, 3] ; vector: '#(1 2 -5 4) ; [,bt for context]
Vyplnění všech prvků vektoru stejnou hodnotou:
(vector-fill! v1 0) v1 '#(0 0 0 0)
Převod vektoru na seznam:
(vector->list v1) '(0 0 0 0) (vector->list v2) '(4 5 6 7) (vector->list v3) '()
Převod seznamu na vektor:
(list->vector '()) '#() (list->vector '(1)) '#(1) (list->vector '(1 2 3)) '#(1 2 3)
Procházení prvky vektoru:
(for/vector ([i v1]) (fx* i i)) '#(1 25 9 16 25)
10. Hešovací tabulky
Dalším velmi užitečným a často používaným strukturovaným datovým typem v programovacím jazyku Racket jsou hešovací tabulky (hash table). Podobně jako u seznamů a vektorů, je možné i u hešovacích tabulek zvolit, zda se má jednat o neměnnou hodnotu či o hodnotu, kterou lze za běhu aplikace modifikovat. Neměnná (immutable) hešovací tabulka se vytvoří pomocí konstruktoru hash, kterému se předá libovolný počet dvojic klíč-hodnota:
(hash "red" "#ff0000" "green" "#00ff00" "blue" "#0000ff") '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000"))
Při porovnávání klíčů prvků vkládaných do hešovací tabulky se používají predikáty equal?, eq? nebo eqv? (eq? provádí nejsilnější porovnání, porovnání je současně nejrychlejší). Výše uvedený konstruktor hash používá predikát equal?, ovšem pochopitelně můžeme zvolit i další dva predikáty. Využívá se přitom odlišných konstruktorů hasheq a hasheqv:
(hasheq "red" "#ff0000" "green" "#00ff00" "blue" "#0000ff") '#hasheq(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000")) (hasheqv "red" "#ff0000" "green" "#00ff00" "blue" "#0000ff") '#hasheqv(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000"))
Měnitelné hešovací tabulky, do nichž je možné v čase přidávat další prvky, se vytváří s využitím konstruktoru make-hash, popř. jeho alternativ make-hasheq a make-hasheqv:
(define h1 (make-hash)) (define h2 (make-hasheq)) (define h3 (make-hasheqv)) h1 '#hash() h2 '#hasheq() h3 '#hasheqv()
Prvky měnitelné hešovací tabulky lze inicializovat, a to předáním seznamu obsahujícího dvojice klíč-hodnota (každá dvojice by měla být podseznamem):
(define h1 (make-hash '(["red" "#ff0000"] ["green" "#00ff00"] ["blue" "#0000ff"]))) (define h2 (make-hasheq '(["red" "#ff0000"] ["green" "#00ff00"] ["blue" "#0000ff"]))) (define h3 (make-hasheqv '(["red" "#ff0000"] ["green" "#00ff00"] ["blue" "#0000f h1 '#hash(("blue" . ("#0000ff")) ("green" . ("#00ff00")) ("red" . ("#ff0000"))) h2 '#hasheq(("blue" . ("#0000ff")) ("green" . ("#00ff00")) ("red" . ("#ff0000"))) h3 '#hasheqv(("blue" . ("#0000ff")) ("green" . ("#00ff00")) ("red" . ("#ff0000")))
Vzhledem k tomu, že hodnota prvku je získána operací cdr (což v našem případě vedlo k vytvoření hodnot tvořených jednoprvkovými seznamy), může být výhodnější při konstrukci hešovací tabulky použít přímo tečka-dvojice:
(make-hash '(["red" . "#ff0000"] ["green" . "#00ff00"] ["blue" . "#0000ff"])) '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000"))
11. Funkce a makra používaná pro práci s hešovacími tabulkami
Přečtení prvku uloženého pod známým klíčem:
(hash-ref h1 "blue") "#0000ff"
Pokus o přečtení neexistujícího prvku:
(hash-ref h1 "foobar") ; hash-ref: no value found for key ; key: "foobar" ; [,bt for context]
Specifikovat lze i hodnotu, která se vrací ve chvíli, kdy prvek nebyl nalezen:
(hash-ref h1 "blue" "nic") "#0000ff" (hash-ref h1 "foobar" "nic") "nic"
Do měnitelných hešovacích tabulek se nová dvojice klíč-hodnota ukládá funkcí hash-set!:
(hash-set! h1 "red" "#ff0000") (hash-set! h1 "green" "#00ff00") (hash-set! h1 "blue" "#0000ff") h1 '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000"))
Přepis hodnoty prvku (se stejným klíčem):
(hash-set! h1 "blue" "rgb(0,0,1)") h1 '#hash(("blue" . "rgb(0,0,1)") ("green" . "#00ff00") ("red" . "#ff0000"))
Odstranění prvku z hešovací tabulky:
(hash-remove! h1 "blue") (hash-remove! h1 "foobar") h1 '#hash(("green" . "#00ff00") ("red" . "#ff0000"))
U neměnitelných hešovacích tabulek se používají funkce hash-set a hash-remove (bez vykřičníku na konci), které ovšem pochopitelně nemodifikují původní tabulku, ale vrací tabulku novou:
(define h1 (hash "red" "#ff0000" "green" "#00ff00" "blue" "#0000ff")) h1 '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000")) (hash-set h1 "white" "#ffffff") '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000") ("white" . "#ffffff")) h1 '#hash(("blue" . "#0000ff") ("green" . "#00ff00") ("red" . "#ff0000"))
12. Generátor číselné řady (typu range)
V praxi se velmi často setkáme s požadavkem vytvoření sekvence čísel. Tento požadavek je v mnoha programovacích jazycích realizován nějakou základní funkcí; příkladem může být jazyk Python 2.x a jeho funkce range (v Pythonu 3 se sémantika této funkce změnila). V jazyku Racket se pro podobný účel používá funkce se jménem in-range, což je jméno, které začne dávat smysl ve chvíli, kdy ji použijeme společně se speciální formou for pro vytvoření programové smyčky. Tato funkce vrací takzvaný proud (stream):
(in-range 10) #
Zkusme však tuto funkci zkombinovat s for/list. Využijeme přitom jak základní variantu funkce, v níž se zadává pouze koncová hodnota, tak i variantu s počáteční hodnotou a (nepovinným) krokem:
(for/list ([i (in-range 10)]) i) '(0 1 2 3 4 5 6 7 8 9) (for/list ([i (in-range 1 10)]) i) '(1 2 3 4 5 6 7 8 9) (for/list ([i (in-range 1 10 2)]) i) '(1 3 5 7 9) (for/list ([i (in-range 1 10 -2)]) i) '() (for/list ([i (in-range 10 0 -2)]) i) '(10 8 6 4 2)
Použití pro zlomky (typ rational):
(for/list ([i (in-range 1 10 1/2)]) i) '(1 3/2 2 5/2 3 7/2 4 9/2 5 11/2 6 13/2 7 15/2 8 17/2 9 19/2)
Použití pro reálná čísla (se známým problémem, který způsobuje hodnota 0,1):
(for/list ([i (in-range 0.0 1 0.1)]) i) '(0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999)
Existuje ještě podobná funkce nazvaná in-naturals, která taktéž generuje číselnou řadu, ovšem v tomto případě nekonečnou (případná programová smyčka tedy nikdy neskončí, pokud v ní nepoužijeme nějakou jinou formu pro ukončení iteračního cyklu):
(for/list ([k (in-naturals)] [x (in-range 10)]) (list k x)) '((0 0) (1 1) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9))
popř.:
(for/list ([k (in-naturals)] [x (in-range 1 10)]) (list k (/ 1 x))) '((0 1) (1 1/2) (2 1/3) (3 1/4) (4 1/5) (5 1/6) (6 1/7) (7 1/8) (8 1/9))
13. Specializované datové typy
V navazujících kapitolách se ve stručnosti seznámíme s dalšími specializovanými datovými typy, které lze v programovacím jazyku Racket použít. V první řadě se jedná o numerický datový typ fixnum, dále o typ flonum, vektory s prvky fixnum a flonum a taktéž o zobecnění sekvencí, které je představováno datovým typem stream.
14. Celočíselné numerické hodnoty s pevným počtem bitů (fixnum)
Běžné aritmetické funkce typu + atd. dokážou pracovat s libovolným numerickým typem z numerické věže jazyka Racket. To je u vysokoúrovňového programovacího jazyka očekávatelné chování, ovšem zaplatíme za to delší dobou výpočtu a případně i větší spotřebou operační paměti. Pokud potřebujeme provádět rychlé výpočty jen s celými čísly (navíc shora omezenými), lze pro tento účel použít hodnoty typu fixnum, což jsou celá čísla (integer) o šířce 31 bitů na 32bitových systémech a 63 bitů na systémech 64bitových (jeden bit je rezervován pro tag).
Aby byly dále popsané funkce volatelné, je nutné nahrát příslušnou knihovnu:
(require racket/fixnum)
Poté lze namísto obecných funkcí +, -, < atd. použít funkci s prefixem „fx“:
(+ 1 2) 3 (fx+ 1 2) 3
Rozdíl mezi + a fx+ se projeví například ve chvíli, kdy překročíme rozsah 31/63 bitů:
(+ 1 4611686018427387903) 4611686018427387904 (fx+ 1 4611686018427387903) ; fx+: result is not a fixnum ; result: 4611686018427387904 ; [,bt for context]
Popř. se pokusíme o násobení velkých čísel, které může vést k přetečení (mezi)výsledku (ovšem bez nahlášení chyby):
(* (* 99999 99999) (* 99999 99999)) 99996000059999600001 (fx* (fx* 99999 99999) (fx* 99999 99999)) -1461092345402933887
Pokud nám nevyhovuje kontrola na chyby přetečení, lze použít „nezabezpečené“ (unsafe) operace:
(require racket/unsafe/ops) (unsafe-fx+ 1 4611686018427387903) -4611686018427387904
Výpočet faktoriálu pouze nad typem fixnum s případným přetečením či dalšími problémy, které mohou nastat:
#lang racket/base (require racket/fixnum) (define (print item) (display item) (newline)) (define (factorial n) (let fact-iter ( ; pomocná vnitřní funkce (n n) ; počitadlo iterací (result 1)) ; průběžný výsledek (if (fx= n 0) ; po dosažení koncového stavu result ; se vrátí průběžný výsledek (fact-iter (fx- n 1) (fx* n result)) ; koncové volání ))) (define n 0) (do () ((>= n 30)) (print (factorial n)) (set! n (+ n 1)))
S výsledky:
1 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 6227020800 87178291200 1307674368000 20922789888000 355687428096000 6402373705728000 121645100408832000 2432902008176640000 -4249290049419214848 -1250660718674968576 fx*: result is not a fixnum result: -28658025453976518656 context...: /home/tester/src/LISP/lisp-families/racket/base-libraries/05-factorial_fixnum.rkt:10:4: fact-iter /home/tester/src/LISP/lisp-families/racket/base-libraries/05-factorial_fixnum.rkt:20:0: doloop "/home/tester/src/LISP/lisp-families/racket/base-libraries/05-factorial_fixnum.rkt": [running body] temp37_0 for-loop run-module-instance!125 perform-require!78
15. Typ fxvector
Datový typ fxvektor odpovídá poli celých čísel z céčka či Javy. Je to tedy strukturovaný datový typ navržený a uložený takovým způsobem, aby umožnil rychlou práci s celými čísly i šířce 31, resp. 63 bitů, v ostatních ohledech se fxvektor chová prakticky stejně, jako klasický datový typ vector.
Vytvoření fxvektoru a dotaz, zda je nějaká hodnota tohoto typu:
(fxvector 1 2 3 4) (fxvector 1 2 3 4) (define v1 (fxvector 1 2 3 4 5)) (fxvector? v1) #t
Základní operace s fxvektory jsou podobné, jako je tomu u běžných vektorů:
(fxvector-length v1) 5 (fxvector-ref v1 1) 2 (fxvector-ref v1 10) ; fxvector-ref: index is out of range ; index: 10 ; valid range: [0, 4] ; fxvector: (fxvector 1 2 3 4 5) ; [,bt for context] (fxvector-set! v1 1 -5) v1 (fxvector 1 -5 3 4 5) (fxvector-set! v1 10 -5) ; fxvector-set!: index is out of range ; index: 10 ; valid range: [0, 4] ; fxvector: (fxvector 1 -5 3 4 5) ; [,bt for context]
Procházení všemi prvky fxvektoru:
(for/fxvector ([i v1]) i) (fxvector 1 -5 3 4 5) (for/fxvector ([i v1]) (fx* i i)) (fxvector 1 25 9 16 25)
16. Typ flvector
Dalším datovým typem, který se do značné míry podobá výše popsanému typu fxvector, je datový typ nazvaný flvector. Již název tohoto typu napovídá, jaké bude mít základní vlastnosti: jedná se o vektor obsahující prvky typu flonum, což je jen zvláštní název pro numerické hodnoty s plovoucí řádovou čárkou s dvojitou přesností podle IEEE 754. Jinými slovy se jedná o typ známý v jiných programovacích jazycích pod jménem double nebo float64.
Před použitím speciálních operací pro typ flonum je zapotřebí naimportovat příslušnou knihovnu:
(require racket/flonum)
Podobně jako u typu fixnum existovaly základní aritmetické a relační funkce s prefixem „fx“, jsou pro datový typ flonum definovány funkce, jejichž prefix je „fl“. Ukažme si několik jednoduchých příkladů.
Pokus o součet dvou hodnot funkcí fl+. Obě hodnoty musí být typu flonum:
(fl+ 10 20) ; fl+: contract violation ; expected: flonum? ; given: 10 ; argument position: 1st ; [,bt for context] (fl+ 10. 20.) 30.0
Výpočet faktoriálu pouze s čísly typu flonum (což je obecně špatný nápad):
#lang racket/base (require racket/flonum) (define (print item) (display item) (newline)) (define (factorial n) (let fact-iter ( ; pomocná vnitřní funkce (n n) ; počitadlo iterací (result 1.0)) ; průběžný výsledek (if (fl= n 0.0) ; po dosažení koncového stavu result ; se vrátí průběžný výsledek (fact-iter (fl- n 1.0) (fl* n result)) ; koncové volání ))) (define n 0.0) (do () ((>= n 30.0)) (print (factorial n)) (set! n (+ n 1)))
S výsledky:
1.0 1.0 2.0 6.0 24.0 120.0 720.0 5040.0 40320.0 362880.0 3628800.0 39916800.0 479001600.0 6227020800.0 87178291200.0 1307674368000.0 20922789888000.0 3.55687428096e+14 6.402373705728e+15 1.21645100408832e+17 2.43290200817664e+18 5.109094217170944e+19 1.1240007277776077e+21 2.585201673888498e+22 6.204484017332394e+23 1.5511210043330984e+25 4.032914611266057e+26 1.0888869450418352e+28 3.048883446117138e+29 8.841761993739701e+30
Deklarace vektoru typu flvector:
(flvector 1. 2. 3.) (flvector 1.0 2.0 3.0) (flvector 1. 2. 3) ; flvector: contract violation ; expected: flonum? ; given: 3 ; argument position: 3rd ; [,bt for context]
17. Typ stream
Posledním důležitým datovým typem, o němž se dnes alespoň ve stručnosti zmíníme, je typ nazvaný stream (proud). Na tento datový typ se můžeme dívat jako na zobecnění sekvencí. Nejdůležitějšími operacemi pro práci se streamem jsou operace představované funkcemi stream-first a stream-rest. Samotný stream je postupně vytvořen funkcí stream-cons, ovšem ve funkci streamu lze použít i běžné lineárně vázané seznamy (list). Čím se tedy vlastně streamy od seznamů odlišují? Seznam musí být konečný a všechny jeho prvky musí být vyhodnoceny, zatímco v případě streamů je možné mít nekonečnou sekvenci prvků a – což vyplývá z předchozího – nemusí být všechny prvky vyhodnoceny, ale jejich vyhodnocení se provádí až ve chvíli, kdy je to nezbytně nutné. Takové streamy nazýváme lazy streams, podobně jako v programovacím jazyce Clojure máme lazy sekvence (ostatně na lazy sekvencích je postavena prakticky celá základní knihovna Clojure).
Aby bylo možné tento datový typ použít, je nutné ve skriptu provést import příslušné knihovny:
(require racket/stream)
Ukažme si nyní (velmi jednoduché) použití streamů. Jak již víme z předchozího textu, lze stream postupně vytvořit funkcí stream-cons, nebo pomocí konstruktoru stream (jenž interně stream-cons volá):
(define s1 (stream 1 2 3 4 5)) s1 #<stream>
Funkce stream-first a stream-rest:
(stream-first s1) 1 (stream-rest s1) #<stream>
Převod streamu na sekvenci:
(in-stream s1) #<sequence>
Převod (konečného!) streamu na seznam:
(stream->list s1) '(1 2 3 4 5)
Získání prvních tří prvků streamu:
(stream-take s1 3) #<stream>
Líná aplikace funkce na všechny prvky streamu:
(define (square x) (* x x)) (stream-map square s1) #<stream> (stream->list (stream-map square s1)) '(1 4 9 16 25)
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 Git repositáře, který je dostupný na adrese https://github.com/tisnik/lisp-families.git (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
19. Literatura
- Peter Seibel
„Practical Common Lisp“
2009 - Paul Graham
„ANSI Common Lisp“
1995 - Gerald Gazdar
„Natural Language Processing in Lisp: An Introduction to Computational Linguistics“
1989 - Peter Norvig
„Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp“
1991 - Alex Mileler et.al.
„Clojure Applied: From Practice to Practitioner“
2015 - „Living Clojure: An Introduction and Training Plan for Developers“
2015 - Dmitri Sotnikov
„Web Development with Clojure: Build Bulletproof Web Apps with Less Code“
2016 - McCarthy
„Recursive functions of symbolic expressions and their computation by machine, part I“
1960 - R. Kent Dybvig
„The Scheme Programming Language“
2009 - Max Hailperin
„Concrete Abstractions“
1998 - Guy L. Steele
„History of Scheme“
2006, Sun Microsystems Laboratories - Kolář J., Muller K.:
„Speciální programovací jazyky“
Praha 1981 - „AutoLISP Release 9, Programmer's reference“
Autodesk Ltd., October 1987 - „AutoLISP Release 10, Programmer's reference“
Autodesk Ltd., September 1988 - McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P.; Levin, Michael I.
„LISP 1.5 Programmer's Manual“
MIT Press. ISBN 0 262 130 1 1 4 - Carl Hewitt; Peter Bishop and Richard Steiger
„A Universal Modular Actor Formalism for Artificial Intelligence“
1973 - Feiman, J.
„The Gartner Programming Language Survey (October 2001)“
Gartner Advisory - Harold Abelson, Gerald Jay Sussman, Julie Sussman:
Structure and Interpretation of Computer Programs
MIT Press. 1985, 1996 (a možná vyšel i další přetisk) - Paul Graham
On Lisp
Prentice Hall, 1993
Dostupné online na stránce http://www.paulgraham.com/onlisptext.html - David S. Touretzky
Common LISP: A Gentle Introduction to Symbolic Computation (Dover Books on Engineering)
- Peter Norvig
Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp - Patrick Winston, Berthold Horn
Lisp (3rd Edition)
ISBN-13: 978–0201083194, ISBN-10: 0201083191 - Matthias Felleisen, David Van Horn, Dr. Conrad Barski
Realm of Racket: Learn to Program, One Game at a Time!
ISBN-13: 978–1593274917, ISBN-10: 1593274912 - Graham Hutton
A tutorial on the universality andexpressiveness of fold
http://www.cs.nott.ac.uk/~pszgmh/fold.pdf
20. Odkazy na Internetu
- Racket: Macros
https://www.it.uu.se/edu/course/homepage/avfunpro/ht13/lectures/Racket-3-Macros.pdf - Beautiful Racket / explainers: Macros
https://beautifulracket.com/explainer/macros.html - Macros (dokumentace k Racketu)
https://docs.racket-lang.org/guide/macros.html - Model syntaxe jazyka Racket
https://docs.racket-lang.org/reference/syntax-model.html - Syntax Objects
https://docs.racket-lang.org/guide/stx-obj.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Beautiful Racket: an introduction to language-oriented programming using Racket
https://beautifulracket.com/ - Stránky projektu Racket
https://racket-lang.org/ - Dokumentace k projektu Racket
https://docs.racket-lang.org/index.html - Seznam dostupných balíčků pro Racket
https://pkgs.racket-lang.org/ - Racket na Wikipedii
https://en.wikipedia.org/wiki/Racket_(programming_language) - Blogy o Racketu a navazujících technologiích
https://blog.racket-lang.org/ - Prográmky psané v Racketu na RosettaCode
http://rosettacode.org/wiki/Category:Racket - Fear of Macros
https://www.greghendershott.com/fear-of-macros/ - Rackjure
https://github.com/greghendershott/rackjure - Matthew Flatt’s proposal to change Racket’s s-expressions based syntax to infix representation creates a stir in the community
https://hub.packtpub.com/matthew-flatts-proposal-to-change-rackets-s-expressions-based-syntax-to-infix-representation-creates-a-stir-in-the-community/ - Racket News
https://racket-news.com/ - Racket: Lisp for learning
https://lwn.net/Articles/795385/ - Future of Racket
https://www.greghendershott.com/2019/07/future-of-racket.html - Kawa: Compiling Scheme to Java
https://www.mit.edu/afs.new/sipb/project/kawa/doc/kawa-tour.html - Kawa in Languages shootout
http://per.bothner.com/blog/2010/Kawa-in-shootout/ - Kawa 2.0 Supports Scheme R7RS
https://developers.slashdot.org/story/14/12/13/2259225/kawa-20-supports-scheme-r7rs/ - Kawa — fast scripting on the Java platform
https://lwn.net/Articles/623349/ - Tail call (a její optimalizace)
https://en.wikipedia.org/wiki/Tail_call - SLIME (Wikipedia)
http://en.wikipedia.org/wiki/SLIME - slime.vim
http://s3.amazonaws.com/mps/slime.vim - What are the best scheme implementations?
https://www.slant.co/topics/5282/~scheme-implementations - Bigloo homepage
http://www-sop.inria.fr/mimosa/fp/Bigloo/ - FTP s tarbally Bigloo
ftp://ftp-sop.inria.fr/indes/fp/Bigloo - GOTO 2018 • Functional Programming in 40 Minutes • Russ Olsen
https://www.youtube.com/watch?v=0if71HOyVjY - TinyScheme (stránka na Sourceforge)
http://tinyscheme.sourceforge.net/home.html - Embedding Tiny Scheme in a Game
http://www.silicondelight.com/embedding-tiny-scheme-in-a-game/ - Embedding Scheme for a game mission scripting DSL
http://carloscarrasco.com/embedding-scheme-for-a-game-mission-scripting-dsl.html - Všechny verze TinyScheme na SourceForge
https://sourceforge.net/projects/tinyscheme/files/tinyscheme/ - Fork TinyScheme na GitHubu
https://github.com/yawnt/tinyscheme - Ackermannova funkce
https://cs.wikipedia.org/wiki/Ackermannova_funkce - Ackermann function na Rosetta Code
https://rosettacode.org/wiki/Ackermann_function#Scheme - Success Stories (lisp.org)
https://lisp-lang.org/success/ - Allegro Common Lisp Success Stories
https://franz.com/success/ - Clojure Success Stories
https://clojure.org/community/success_stories - Scheme Quick Reference
https://www.st.cs.uni-saarland.de/edu/config-ss04/scheme-quickref.pdf - Slajdy o Scheme (od slajdu číslo 15)
https://docs.google.com/presentation/d/1abmDnKjrq1tcjGvvRNAKhOiSTSE2lyagtcEPal07Gbo/edit - Scheme Cheat Sheet
https://github.com/smythp/scheme-cheat-sheet - Embedding Lua, embedding Guile
http://puntoblogspot.blogspot.com/2013/04/embedding-lua-embedding-guile.html - Lambda Papers
https://en.wikisource.org/wiki/Lambda_Papers - Revised7Report on the Algorithmic Language Scheme
https://small.r7rs.org/attachment/r7rs.pdf - Video Lectures (MIT, SICP 2005)
https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6–001-structure-and-interpretation-of-computer-programs-spring-2005/video-lectures/ - Why is Scheme my first language in university?
https://softwareengineering.stackexchange.com/questions/115252/why-is-scheme-my-first-language-in-university - The Perils of JavaSchools
https://www.joelonsoftware.com/2005/12/29/the-perils-of-javaschools-2/ - How to Design Programs, Second Edition
https://htdp.org/2019–02–24/index.html - LilyPond
http://lilypond.org/ - LilyPond — Extending (přes Scheme)
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-tutorial - Scheme in LilyPond
http://lilypond.org/doc/v2.18/Documentation/extending/scheme-in-lilypond - GnuCash
http://www.gnucash.org/ - Custom Reports (in GNU Cash)
https://wiki.gnucash.org/wiki/Custom_Reports - Program by Design
https://programbydesign.org/ - SchemePy
https://pypi.org/project/SchemePy/ - LISP FQA: Section – [1–5] What is the „minimal“ set of primitives needed for a Lisp interpreter?
http://www.faqs.org/faqs/lisp-faq/part1/section-6.html - femtolisp
https://github.com/JeffBezanson/femtolisp - (How to Write a (Lisp) Interpreter (in Python))
http://norvig.com/lispy.html - Repositář s Guile Emacsem
http://git.hcoop.net/?p=bpt/guile.git - Interacting with Guile Compound Data Types in C
http://www.lonelycactus.com/guilebook/x1555.html - Calling Guile functions from C
http://www.lonelycactus.com/guilebook/c1204.html#SECCALLGUILEFUNC - Arrays, and other compound data types
http://www.lonelycactus.com/guilebook/charrays.html - Interacting with Guile Compound Data Types in C
http://www.lonelycactus.com/guilebook/x1555.html - Guile Reference Manual
https://www.gnu.org/software/guile/manual/html_node/index.html - Scheme: Summary of Common Syntax
https://www.gnu.org/software/guile/manual/html_node/Syntax-Summary.html#Syntax-Summary - Scripting with Guile: Extension language enhances C and Scheme
https://www.ibm.com/developerworks/library/l-guile/index.html - Having fun with Guile: a tutorial
http://dustycloud.org/misc/guile-tutorial.html - Guile: Loading Readline Support
https://www.gnu.org/software/guile/manual/html_node/Loading-Readline-Support.html#Loading-Readline-Support - lispy
https://pypi.org/project/lispy/ - Lython
https://pypi.org/project/Lython/ - Lizpop
https://pypi.org/project/lizpop/ - Budoucnost programovacích jazyků
http://www.knesl.com/budoucnost-programovacich-jazyku - LISP Prolog and Evolution
http://blog.samibadawi.com/2013/05/lisp-prolog-and-evolution.html - List of Lisp-family programming languages
https://en.wikipedia.org/wiki/List_of_Lisp-family_programming_languages - clojure_py na indexu PyPi
https://pypi.python.org/pypi/clojure_py - PyClojure
https://github.com/eigenhombre/PyClojure - Hy na GitHubu
https://github.com/hylang/hy - Hy: The survival guide
https://notes.pault.ag/hy-survival-guide/ - Hy běžící na monitoru terminálu společnosti Symbolics
http://try-hy.appspot.com/ - Welcome to Hy’s documentation!
http://docs.hylang.org/en/stable/ - Hy na PyPi
https://pypi.org/project/hy/#description - Getting Hy on Python
https://lwn.net/Articles/596626/ - Programming Can Be Fun with Hy
https://opensourceforu.com/2014/02/programming-can-fun-hy/ - Přednáška o projektu Hy (pětiminutový lighttalk)
http://blog.pault.ag/day/2013/04/02 - Hy (Wikipedia)
https://en.wikipedia.org/wiki/Hy - GNU Emacs Lisp Reference Manual: Point
https://www.gnu.org/software/emacs/manual/html_node/elisp/Point.html - GNU Emacs Lisp Reference Manual: Narrowing
https://www.gnu.org/software/emacs/manual/html_node/elisp/Narrowing.html - GNU Emacs Lisp Reference Manual: Functions that Create Markers
https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Markers.html - GNU Emacs Lisp Reference Manual: Motion
https://www.gnu.org/software/emacs/manual/html_node/elisp/Motion.html#Motion - GNU Emacs Lisp Reference Manual: Basic Char Syntax
https://www.gnu.org/software/emacs/manual/html_node/elisp/Basic-Char-Syntax.html - Elisp: Sequence: List, Array
http://ergoemacs.org/emacs/elisp_list_vs_vector.html - Elisp: Property List
http://ergoemacs.org/emacs/elisp_property_list.html - Elisp: Hash Table
http://ergoemacs.org/emacs/elisp_hash_table.html - Elisp: Association List
http://ergoemacs.org/emacs/elisp_association_list.html - The mapcar Function (An Introduction to Programming in Emacs Lisp)
https://www.gnu.org/software/emacs/manual/html_node/eintr/mapcar.html - Anaphoric macro
https://en.wikipedia.org/wiki/Anaphoric_macro - Some Common Lisp Loop Macro Examples
https://www.youtube.com/watch?v=3yl8o6r_omw - A Guided Tour of Emacs
https://www.gnu.org/software/emacs/tour/ - The Roots of Lisp
http://www.paulgraham.com/rootsoflisp.html - Evil (Emacs Wiki)
https://www.emacswiki.org/emacs/Evil - Evil (na GitHubu)
https://github.com/emacs-evil/evil - Evil (na stránkách repositáře MELPA)
https://melpa.org/#/evil - Evil Mode: How I Switched From VIM to Emacs
https://blog.jakuba.net/2014/06/23/evil-mode-how-to-switch-from-vim-to-emacs.html - GNU Emacs (home page)
https://www.gnu.org/software/emacs/ - GNU Emacs (texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?GnuEmacs - An Introduction To Using GDB Under Emacs
http://tedlab.mit.edu/~dr/gdbintro.html - An Introduction to Programming in Emacs Lisp
https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html - 27.6 Running Debuggers Under Emacs
https://www.gnu.org/software/emacs/manual/html_node/emacs/Debuggers.html - GdbMode
http://www.emacswiki.org/emacs/GdbMode - Emacs (Wikipedia)
https://en.wikipedia.org/wiki/Emacs - Emacs timeline
http://www.jwz.org/doc/emacs-timeline.html - Emacs Text Editors Family
http://texteditors.org/cgi-bin/wiki.pl?EmacsFamily - Vrapper aneb spojení možností Vimu a Eclipse
https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse/ - Vrapper aneb spojení možností Vimu a Eclipse (část 2: vyhledávání a nahrazování textu)
https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse-cast-2-vyhledavani-a-nahrazovani-textu/ - Emacs/Evil-mode – A basic reference to using evil mode in Emacs
http://www.aakarshnair.com/posts/emacs-evil-mode-cheatsheet - From Vim to Emacs+Evil chaotic migration guide
https://juanjoalvarez.net/es/detail/2014/sep/19/vim-emacsevil-chaotic-migration-guide/ - Introduction to evil-mode {video)
https://www.youtube.com/watch?v=PeVQwYUxYEg - EINE (Emacs Wiki)
http://www.emacswiki.org/emacs/EINE - EINE (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?EINE - ZWEI (Emacs Wiki)
http://www.emacswiki.org/emacs/ZWEI - ZWEI (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?ZWEI - Zmacs (Wikipedia)
https://en.wikipedia.org/wiki/Zmacs - Zmacs (Texteditors.org)
http://texteditors.org/cgi-bin/wiki.pl?Zmacs - TecoEmacs (Emacs Wiki)
http://www.emacswiki.org/emacs/TecoEmacs - Micro Emacs
http://www.emacswiki.org/emacs/MicroEmacs - Micro Emacs (Wikipedia)
https://en.wikipedia.org/wiki/MicroEMACS - EmacsHistory
http://www.emacswiki.org/emacs/EmacsHistory - Seznam editorů s ovládáním podobným Emacsu či kompatibilních s příkazy Emacsu
http://www.finseth.com/emacs.html - evil-numbers
https://github.com/cofi/evil-numbers - Debuggery a jejich nadstavby v Linuxu (1.část)
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/ - Debuggery a jejich nadstavby v Linuxu (2.část)
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/ - Debuggery a jejich nadstavby v Linuxu (3): Nemiver
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/ - Debuggery a jejich nadstavby v Linuxu (4): KDbg
http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/ - Debuggery a jejich nadstavby v Linuxu (5): ladění aplikací v editorech Emacs a Vim
https://mojefedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-5-ladeni-aplikaci-v-editorech-emacs-a-vim/ - Org mode
https://orgmode.org/ - The Org Manual
https://orgmode.org/manual/index.html - Kakoune (modální textový editor)
http://kakoune.org/ - Vim-style keybinding in Emacs/Evil-mode
https://gist.github.com/troyp/6b4c9e1c8670200c04c16036805773d8 - Emacs – jak začít
http://www.abclinuxu.cz/clanky/navody/emacs-jak-zacit - Programovací jazyk LISP a LISP machines
https://www.root.cz/clanky/programovaci-jazyk-lisp-a-lisp-machines/ - Evil-surround
https://github.com/emacs-evil/evil-surround - Spacemacs
http://spacemacs.org/ - Lisp: Common Lisp, Racket, Clojure, Emacs Lisp
http://hyperpolyglot.org/lisp - Common Lisp, Scheme, Clojure, And Elisp Compared
http://irreal.org/blog/?p=725 - Does Elisp Suck?
http://irreal.org/blog/?p=675 - Emacs pro mírně pokročilé (9): Elisp
https://www.root.cz/clanky/emacs-elisp/ - If I want to learn lisp, are emacs and elisp a good choice?
https://www.reddit.com/r/emacs/comments/2m141y/if_i_want_to_learn_lisp_are_emacs_and_elisp_a/ - Clojure(Script) Interactive Development Environment that Rocks!
https://github.com/clojure-emacs/cider - An Introduction to Emacs Lisp
https://harryrschwartz.com/2014/04/08/an-introduction-to-emacs-lisp.html - Emergency Elisp
http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html - Lambda calculus
https://en.wikipedia.org/wiki/Lambda_calculus - John McCarthy's original LISP paper from 1959
https://www.reddit.com/r/programming/comments/17lpz4/john_mccarthys_original_lisp_paper_from_1959/ - Micro Manual LISP
https://www.scribd.com/document/54050141/Micro-Manual-LISP - How Lisp Became God's Own Programming Language
https://twobithistory.org/2018/10/14/lisp.html - History of Lisp
http://jmc.stanford.edu/articles/lisp/lisp.pdf - The Roots of Lisp
http://languagelog.ldc.upenn.edu/myl/llog/jmc.pdf - Racket
https://racket-lang.org/ - The Racket Manifesto
http://felleisen.org/matthias/manifesto/ - MIT replaces Scheme with Python
https://www.johndcook.com/blog/2009/03/26/mit-replaces-scheme-with-python/ - Adventures in Advanced Symbolic Programming
http://groups.csail.mit.edu/mac/users/gjs/6.945/ - Why MIT Switched from Scheme to Python (2009)
https://news.ycombinator.com/item?id=14167453 - Starodávná stránka XLispu
http://www.xlisp.org/ - AutoLISP
https://en.wikipedia.org/wiki/AutoLISP - Seriál PicoLisp: minimalistický a výkonný interpret Lispu
https://www.root.cz/serialy/picolisp-minimalisticky-a-vykonny-interpret-lispu/ - Common Lisp
https://common-lisp.net/ - Getting Going with Common Lisp
https://cliki.net/Getting%20Started - Online Tutorial (Common Lisp)
https://cliki.net/online%20tutorial - Guile Emacs
https://www.emacswiki.org/emacs/GuileEmacs - Guile Emacs History
https://www.emacswiki.org/emacs/GuileEmacsHistory - Guile is a programming language
https://www.gnu.org/software/guile/ - MIT Scheme
http://groups.csail.mit.edu/mac/projects/scheme/ - SIOD: Scheme in One Defun
http://people.delphiforums.com/gjc//siod.html - CommonLispForEmacs
https://www.emacswiki.org/emacs/CommonLispForEmacs - Elisp: print, princ, prin1, format, message
http://ergoemacs.org/emacs/elisp_printing.html - Special Forms in Lisp
http://www.nhplace.com/kent/Papers/Special-Forms.html - Basic Building Blocks in LISP
https://www.tutorialspoint.com/lisp/lisp_basic_syntax.htm - Introduction to LISP – University of Pittsburgh
https://people.cs.pitt.edu/~milos/courses/cs2740/Lectures/LispTutorial.pdf - Why don't people use LISP
https://forums.freebsd.org/threads/why-dont-people-use-lisp.24572/ - Structured program theorem
https://en.wikipedia.org/wiki/Structured_program_theorem - Clojure: API Documentation
https://clojure.org/api/api - Tutorial for the Common Lisp Loop Macro
http://www.ai.sri.com/pkarp/loop.html - Common Lisp's Loop Macro Examples for Beginners
http://www.unixuser.org/~euske/doc/cl/loop.html - A modern list api for Emacs. No 'cl required.
https://github.com/magnars/dash.el - The LOOP Facility
http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - Transient Data Structureshttp://clojure.org/transients
- Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Jazyky Hy a Clojure-py: moderní dialekty LISPu určené pro Python VM
https://www.root.cz/clanky/jazyky-hy-a-clojure-py-moderni-dialekty-lispu-urcene-pro-python-vm/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Stránka projektu Jython
http://www.jython.org/ - Jython (Wikipedia)
https://en.wikipedia.org/wiki/Jython - Scripting for the Java Platform (Wikipedia)
https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - JSR 223: Scripting for the JavaTM Platform
https://jcp.org/en/jsr/detail?id=223 - List of JVM languages
https://en.wikipedia.org/wiki/List_of_JVM_languages - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354