Hlavní navigace

Femtolisp: dialekt LISPu tvořící součást jazyka Julia

20. 1. 2022
Doba čtení: 56 minut

Sdílet

 Autor: Depositphotos
Na Rootu již vyšlo více než dvacet článků o různých dialektech jazyků LISP a Scheme. Další dialekt, s nímž se seznámíme dnes, se jmenuje Femtolisp. Jedná se o LISP v tradičním pojetí, který je součástí překladače jazyka Julia.

Obsah

1. Femtolisp: varianta LISPu tvořící součást jazyka Julia

2. Různé implementace programovacího jazyka Scheme

3. Dialekty LISPu

4. Femtolisp jako součást programovacího jazyky Julia

5. Překlad Femtolispu s bootstrapingem

6. Skutečně minimalistická implementace?

7. Vylepšení REPLu jazyka Femtolisp

8. Základní vlastnosti jazyka Femtolisp

9. Funkce a speciální formy

10. Pojmenované funkce s proměnným počtem parametrů

11. Povinné a nepovinné parametry pojmenovaných funkcí

12. Koncová rekurze

13. Typový systém Femtolispu

14. Lokální rozsah proměnných

15. Makrosystém

16. Reálné použití Femtolispu

17. Repositář s demonstračními příklady

18. Předchozí části seriálu

19. Literatura

20. Odkazy na Internetu

1. Femtolisp: varianta LISPu tvořící součást jazyka Julia

„Almost everybody has their own lisp implementation. Some programmers' dogs and cats probably have their own lisp implementations as well. This is great, but too often I see people omit some of the obscure but critical features that make lisp uniquely wonderful. These include read macros like #. and backreferences, gensyms, and properly escaped symbol names. If you're going to waste everybody's time with yet another lisp, at least do it right damnit.“
Jeff Bezanson, autor jazyka Femtolisp a spoluautor jazyka Julia

Na stránkách Roota jsme si – jak již ostatně bylo zmíněno v perexu dnešního článku – popsali relativně velké množství různých dialektů a implementací programovacích jazyků LISP a Scheme (viz též osmnáctou kapitolu s odkazy na jednotlivé články o tomto tématu). Jednotlivé implementace se od sebe odlišují jak poskytovanými možnostmi (některé dialekty například nepodporují tradiční LISPovské tečka-dvojice, další zase nemají plnohodnotné TCO), podporou či naopak nepodporou nějakého standardu (R5RS, R6RS, R7RS, ANSI CommonLISP), tak i použitými technologiemi. V prozatím popsaných projektech tedy můžeme najít jak klasické interpretry, tak i překladače, a to buď překladače do strojového kódu, překladače do bajtkódu (JVM, WebAssembly), použití just-in-time překladače atd. Jednotlivé implementace se od sebe odlišují taktéž použitým správcem paměti (garbage collector) – což je technologie, která do značné míry ovlivňuje úspěch či neúspěch implementace LISPu/Scheme v produkčním prostředí.

lisp01

Obrázek 1: Na tomto grafu evoluce programovacích jazyků můžeme vidět některé historicky významné programovací jazyky, s nimiž jsme se již setkali v seriálu o historii počítačů. Jedná se zejména o Fortran, Cobol, SNOBOL, Algol, APL, BASIC (resp. přesněji řečeno celá rodina jazyků nesoucích toho jméno) a samozřejmě taktéž o LISP a jeho varianty.

Poznámka: některé implementace Scheme či LISPu prošly dlouhým vývojem, během něhož došlo ke změně technologií, na nichž jsou postaveny, a to většinou bez nutnosti měnit zdrojové kódy programů napsaných v těchto jazycích. Typickým příkladem je GNU Guile, u něhož došlo ke změně technologie ve verzi 2.0 (Boehm–Demers–Weiser GC) a posléze taktéž ve verzi 2.2 (nový optimalizující překladač a nový virtuální stroj). To vedlo k urychlení reálných programů až o 30%.

Obrázek 2: Alonzo Church, autor slavného lambda kalkulu, na němž jsou nepřímo postaveny všechny LISPovské jazyky.

2. Různé implementace programovacího jazyka Scheme

V případě, že se zaměříme na projekty implementující nějaký standard jazyka Scheme (a reálně použitelných a nasaditelných implementací Scheme dnes existuje přibližně padesát!), můžeme tyto projekty rozdělit do několika skupin:

  1. V první skupině nalezneme klasické interpretry běžící nad nějakým virtuálním strojem popř. překladače do bajtkódu těchto virtuálních strojů. Do této kategorie patří například Gauche, již v úvodní kapitole zmíněný GNU Guile, systém Kawa, Scheme48, SISC (Second Interpreter of Scheme), SCM či Ypsilon (ten se používá pro programování pravidel pinballů, resp. video verzí těchto her). Některé ze zmíněných implementací Scheme používají vlastní virtuální stroj (Guile), další pak nějakou již existující variantu virtuálního stroje (Kawa, SISC). Z modernějších virtuálních strojů (resp. bajtkódů pro ně) je nutné zmínit WebAssembly. Existují minimálně dvě implementace Scheme pro WebAssembly – Schism a PollRobots scheme.
  2. Ve druhé skupině, která je relativně rozsáhlá, nalezneme překladače programovacího jazyka Scheme do nativního (strojového) kódu. Do této kategorie můžeme zařadit například Chez Scheme (ten získal nejlepší hostname pro svoji domácí stránku), Ikarus, Larceny, MIT Scheme, MzScheme či již popsaný rozsáhlý systém Racket založený na MzScheme, který je mj. používán i pro výuku (a to mj. i proto, že obsahuje vlastní GUI, podporu pro tvorbu grafů, interpretry dalších jazyků, mnohá rozšíření syntaxe založená na systému maker apod.).
  3. A konečně existuje i skupina implementací programovacího jazyka Scheme založená na transpřekladači (transcompileru, transpileru), typicky s výstupem do programovacího jazyka C. To znamená, že se vstupní kód napsaný v jazyce Scheme analyzuje, transformuje a optimalizuje, ovšem výstupem není přímo strojový kód, ale více či méně čitelný kód naprogramovaný v jazyku C (a teoreticky samozřejmě i do jiného jazyka, podle mě by byl v této roli ideální jazyk Rust). Do této skupiny řadíme především čtveřici Bigloo, Chicken, Gambit-C a Stalin. Do této skupiny patří i projekt Gambit a Loko Scheme (taktéž se zajímavou doménou). Ovšem transpřekladačem může být vybavena i implementace SISC zmíněná v první skupině (tento transpřekladač se jmenuje Hobbit).

hist26

Obrázek 3: Jedna z mnoha knih o jazyce Scheme.

Poznámka: existují i další možnosti, jak Scheme implementovat. Například se může jednat o implementaci naprogramovanou v JavaScriptu, která může běžet přímo ve webovém prohlížeči, podobně jako již popsaný jazyk WISP, o němž se ještě zmíníme v navazující kapitole. Příkladem této implementace Scheme je BiwaScheme.

3. Dialekty LISPu

„The default language, embodied in a succession of popular languages, has gradually evolved toward Lisp.“
Paul Graham

Ve světě programovacího jazyka LISP je situace chaotičtější a současně i zajímavější, než je tomu v případě Scheme (jehož varianty typicky podporují R5RS, R6RS a blíží se k R7RS). Jednotlivé implementace LISPu totiž nemusí striktně odpovídat nějakému standardu (tedy obdobě RnRS). Nepsaným standardem v této oblasti je sice Common Lisp (přesněji ANSI Common Lisp je standard, ovšem zbytečně nabobtnalý), ovšem jen několik dalších implementací LISPu se tomuto jazyku přibližuje. Neexistence všemi akceptovaného standardu vedla k tomu, že vzniklo mnoho alternativních dialektů LISPu popř. různých kombinací LISPu a Scheme (mimochodem: právě do této kategorie lze zařadit i dnes popisovaný Femtolisp). Příkladem odklonu od dosti rozsáhlého Common Lispu může být PicoLisp, což je interpret LISPu pojatý striktně minimalisticky – a ve své základní variantě odlišný od ostatních implementací LISPu. Zdrojové kódy PicoLispu přitom existují ve dvou variantách. Pro všechny 32bitové procesory (a pro architektury odlišné od x86_64, tedy i pro ARM atd.) se používá varianta naprogramovaná v programovacím jazyce C, pro 64bitové procesory řady x86_64 se pak používá varianta, v níž je část zdrojových kódů vytvořena v assembleru a je vůči céčkové variantě optimalizována (jak s ohledem na velikost, tak i rychlost interpretace).

Obrázek 4: Vývoj některých dialektů Lispu.
Zdroj: Wikipedia.

Samostatnou kapitolou je pak Interlisp, což původně byl dialekt LISPu, který zavedl některé nové zajímavé technologie a díky své historii je velmi zajímavý i v pohledu na vývoj celého IT. Interlisp (psaný původně verzálkami, tedy INTERLISP či InterLisp) se lišil od většiny tehdejších interpretrů. Původní Lispy totiž do značné míry vypadaly tak, jako například dnešní GNU Guile nebo dnes popisovaný Femtolisp – všechny formy musely být zapsány jako s-výrazy, přičemž se netolerovaly žádné chyby, závorky musely být balancovány atd. Interlisp byl v tomto ohledu dosti odlišný. Zejména byly rozšířeny možnosti nástrojů dodávaných společně s tímto jazykem – přidán byl například v té době přelomový korektor překlepů, přidány byly balíčky pro práci se soubory, balíček CLISP umožňující zápis algebraických výrazů, programátorský editor pro strukturovaný kód atd. Pro moderní platformy lze namísto původního Interlispu využít projekt nazvaný přímočaře LISPF4 – InterLisp Interpreter, který je možné nalézt na GitHubu, konkrétně na adrese https://github.com/blakem­cbride/LISPF4. V rámci tohoto projektu došlo k přepsání těch částí Interlispu, které byly původně vytvořeny v assembleru (a to v assembleru pro dobové mainframy a minipočítače). Přepisem těchto obecně velmi těžko přenositelných částí do programovacího jazyka C se zajistila mnohem snadnější přenositelnost, takže dnes pro překlad stačí Linux se základními nástroji GNU toolchainu (překladač jazyka C, linker).

Obrázek 5: Úvodní obrazovka Interlispu/65, což je varianta Intelispu pro osmibitové mikroprocesory MOS 6502.

A nesmíme zapomenout ani na transpilery, mezi něž patří například jazyk Hy, jemuž jsme se na stránkách Roota taktéž věnovali. Programovací jazyk Hy je určen pro ekosystém jazyka Python. Programátorem zapsaný kód transformuje do Pythonu s využitím AST a dokonce dokáže zdrojový LISPovský kód transformovat do Pythonu a teprve poté ho spustit. To je výhodná vlastnost, protože umožňuje Hy integrovat například s existujícími debuggery atd. Překlad přes AST nebo Python podporuje jak Python 2.x, tak i Python 3.x. Další důležitou vlastností Hy je možnost plné kooperace mezi kódem zapsaným přímo v tomto jazyku a Pythoním kódem, což znamená, že je možné použít všechny Pythonovské knihovny a frameworky (včetně Numpy, PyTorch, Flask atd.) a naopak – například mít napsanou aplikaci v Pythonu a pro manipulaci se symboly použít Hy (v tomto ohledu jsou homoikonické programovací jazyky s makry podle mého názoru mnohem lepší než samotný Python, ostatně na tomto konceptu staví i jazyk Julia).

Obrázek 6: Hra Abuse je z velké části napsána v LISPu – nízkoúrovňové části používají nativní knihovny (na Linuxu například SDL), ovšem veškerá herní logika je skutečně v LISPu a s troškou vůle a volného času lze z Abuse vytvořit zcela odlišnou hru. Zdánlivá malá výkonnost LISPu se zde neprojevuje, protože Abuse lze bez problémů hrát i na stařičkém počítači s mikroprocesorem 80486DX2 (ostatně nízká výkonnost LISPu je pro mnoho jeho implementací spíše legendou, než faktem).

Poznámka: samostatnou kategorií je jazyk Clojure a některé jeho dialekty, mezi které patří například poněkud přehlížený projekt Wisp (neboli Web Lisp). Clojure není ani klasickým LISPem ani Scheme, ale jazykem postaveným nad myšlenkami původního LISPu a upraveným tak, aby podporoval různé mechanismy řízení stavu programů (což je asi nejdůležitějším přínosem tohoto jazyka).

Obrázek 7: Specifikem Interlispu/65 je existence funkcí POKE, PEEK, STICK atd., tedy funkcí známých z Atari BASICu a důležitých pro vývoj reálných aplikací. Zde se s využitím funkce POKE změnil obsah barvového registru s barvou pozadí obrazovky v textovém režimu.

4. Femtolisp se představuje

„You mean, how much you can develop during a PhD on scientific computing with a known technical computing syntax and paradigm on top of a modular compiler infrastructure with an enthusiastic community?“

Dnes popisovaný dialekt jazyka LISP (resp. spíše Scheme, které je samo o sobě dialekt LISPu) se jmenuje Femtolisp. Za vývojem tohoto programovacího jazyka, jehož zdrojové kódy i (poněkud stručnou) dokumentaci najdete na https://github.com/JeffBe­zanson/femtolisp, stojí Jeff Bezanson, který je ovšem známější jako spoluautor programovacího jazyka Julia. Jeff se kromě dalších věcí z oblasti computer science zabývá i typovými systémy, viz též text jeho doktorské práce (ostatně i jemu můžeme vděčit za typový systém Julie). Femtolisp je sice relativně minimalistickou implementací LISPu/Scheme, ovšem obsahuje prakticky všechny důležité ikredience tohoto jazyka, a to včetně podpory TCO a makrosystému. Jednou z chybějících věcí je podpora pro „dlouhá“ celá čísla a pro zlomky, což Femtolisp odlišuje například od již popsaného projektu Guile.

Z praktického hlediska je důležité, že Femtolisp je dnes součástí již zmíněného jazyka Julia, protože je použit pro parsing zdrojových kódů. Ostatně právě poměrně pokročilý makrosystém jazyka Julia je umožněn tím, že je parsing naprogramován pravě ve Femtolispu, tedy v jazyku, v němž je manipulace se stromy (AST) snadná. V rámci zpracování zdrojových kódů se totiž provádí několik operací, mezi jinými i transformace podobná této:

f(a, b) = sum(a' * b + a * b')
 
Main.sum(Main.+(Main.Ac_mul_B(a,b),Main.A_mul_Bc(a,b)))

Příklady využití Femtolispu naleznete přímo v repositáři jazyka Julia, například v souborech ast.scm a jlfrontend.scm.

O přítomnosti Femtolispu v jazyce Julia se můžeme snadno přesvědčit. Standardní REPL tohoto jazyka se spouští takto:

$ julia
 
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.5.3 (2020-11-09)
 _/ |\__'_|_|_|\__'_|  |  Fedora 33 build
|__/                   |

Ovšem po zadání přepínače –lisp se spustí REPL jiného jazyka, konkrétně Femtolispu:

$ julia --lisp
 
;  _
; |_ _ _ |_ _ |  . _ _
; | (-||||_(_)|__|_)|_)
;-------------------|----------------------------------------------------------
Poznámka: mimochodem, aby se kruh uzavřel, je možné díky modulu LispSyntax.jl psát programy v LISPovské stylu i přímo v REPLu jazyka Julia.

5. Překlad Femtolispu s bootstrapingem

Získání funkční verze Femtolispu je snadné. Postačuje pouze použít základní vývojářské nástroje, konkrétně Git, Make a GNU C (popř. jiný překladač programovacího jazyka C). Nejprve je pochopitelně nutné získat zdrojové kódy:

$ git clone https://github.com/JeffBezanson/femtolisp.git
 
Cloning into 'femtolisp'...
remote: Enumerating objects: 2412, done.
remote: Total 2412 (delta 0), reused 0 (delta 0), pack-reused 2412
Receiving objects: 100% (2412/2412), 1.60 MiB | 2.20 MiB/s, done.
Resolving deltas: 100% (1498/1498), done.

Vlastní překlad je prováděn v několika fázích, protože je podporován takzvaný bootstraping. Nejdříve se přeloží jen ta nejzákladnější varianta jazyka a teprve poté všechny potřebné symboly a funkce:

$ cd femtolisp
$ make
 
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c flisp.c -o flisp.o
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c builtins.c -o builtins.o
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c string.c -o string.o
string.c: In function ‘fl_string_width’:
string.c:56:21: warning: implicit declaration of function ‘wcwidth’ [-Wimplicit-function-declaration]
   56 |             int w = wcwidth(*(uint32_t*)cp_data(cp));
      |                     ^~~~~~~
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c equalhash.c -o equalhash.o
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c table.c -o table.o
...
...
...
gcc -O3 -DNDEBUG -Wall -Wno-strict-aliasing  -c lltinit.c -o lltinit.o
rm -rf libllt.a
ar rs libllt.a bitvector.o hashing.o socket.o timefuncs.o ptrhash.o utf8.o ios.o dirpath.o htable.o bitvector-ops.o int2str.o dump.o random.o lltinit.o
ar: creating libllt.a
make[1]: Leaving directory '/home/ptisnovs/temp/femtolisp/llt'
rm -rf libflisp.a
ar rs libflisp.a flisp.o builtins.o string.o equalhash.o table.o iostream.o
ar: creating libflisp.a
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO -c flmain.c -o flmain.o
gcc -O2 -DNDEBUG -falign-functions -Wall -Wno-strict-aliasing -Illt  -DUSE_COMPUTED_GOTO flisp.o builtins.o string.o equalhash.o table.o iostream.o flmain.o -o flisp llt/libllt.a -lm libflisp.a

Samotná definice bootstrapingu vypadá přibližně následovně. Povšimněte si, že se první minimalisticky pojatá verze Femtolispu použije pro vytvoření základní knihovny tvořící prakticky nedílnou součást virtuálního stroje tohoto jazyka:

#!/bin/sh
 
cp flisp.boot flisp.boot.bak
 
echo "Creating stage 0 boot file..."
#../../branches/interpreter/femtolisp/flisp mkboot0.lsp system.lsp compiler.lsp > flisp.boot.new
./flisp mkboot0.lsp system.lsp compiler.lsp > flisp.boot.new
mv flisp.boot.new flisp.boot
 
echo "Creating stage 1 boot file..."
./flisp mkboot1.lsp
 
echo "Testing..."
make test

Na konci se automaticky spustí testy, které ověří základní vlastnosti nově přeloženého interpretru:

cd tests && ../flisp unittest.lsp
all tests pass

Výsledkem překladu jsou dva soubory: spustitelný interpret flisp a dále soubor flisp.boot se základními funkcemi, ovšem přeloženými do „bajtkódu“ (nejedná se ovšem o skutečný bajtkód v původním významu tohoto slova). Pro další práci budete skutečně potřebovat pouze tyto dva soubory.

Ověření výsledků překladu:

$ file flisp
flisp: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=685356fb92af78d4addae34f30047683e0299afc, for GNU/Linux 3.2.0, not stripped

Nyní si můžeme vyzkoušet spuštění interpretru:

$ ./flisp

Zobrazit by se mělo logo Femtolispu následované výzvou (prompt):

;  _
; |_ _ _ |_ _ |  . _ _
; | (-||||_(_)|__|_)|_)
;-------------------|----------------------------------------------------------
 
>

Otestujeme, zda interpret reaguje na základní formu:

> (+ 1 2)
3
Poznámka: v naklonovaném repositáři je ještě jedna varianta Lispu, která je menší. Naleznete ji v podadresáři tiny:
$ cd tiny
 
$ make
gcc -O3 -fomit-frame-pointer -Wall -Wextra lisp.c -o lisp
 
$ ls -l lisp
-rwxrwxr-x 1 ptisnovs ptisnovs 31560 Jan 15 17:09 lisp
 
$ ./lisp
Welcome to femtoLisp ----------------------------------------------------------

Touto variantou se však nebudeme v dalším textu zabývat. Snad jen stojí za povšimnutí velikost výsledného binárního souboru – relativně malý interpret o velikosti 31560 bajtů.

6. Skutečně minimalistická implementace?

Původně byl Femtolisp pojat (alespoň podle slov svého autora) přísně minimalisticky, a to jak s ohledem na velikost výsledného binárního kódu s jazykem, tak i s ohledem na množství podporovaných knihoven. Postupně se však jak vlastní jazyk, tak i množství podporovaných knihoven rozrostlo, takže Femtolisp již – i přes své jméno – nepatří mezi nejmenší prakticky použitelný dialekt LISPu či Scheme. Vzhledem k tomu, že jsem v minulosti používal jazyky, jejichž velikost spustitelného souboru byla 8kB (klasické verze BASICů), 4kB (základní verze jazyka BASIC) či pouze 1 kB (Forth), pochopitelně mě zajímalo, jak malý či naopak velký je Femtolisp po svém překladu. Ostatně se můžeme podívat do následující tabulky, v níž jsou vypsány velikosti některých malých (podle tvrzení autorů) implementací LISPu a Scheme. Pro porovnání s mainstreamem jsem ještě přidal velikosti interpretrů dalších programovacích jazyků. Všechny získané velikosti přitom platí pro architekturu x86_64, případné balíčky pochází z Linux Mintu (ovšem LISPy a Scheme jsem překládal přímo ze zdrojových kódů):

# Interpret/VM Velikost Poznámka
1 Femtolisp   176 296 po strip
2 tiny Femtolisp    31 560 alternativní implementace zmíněná výše
3 picolisp   195 272  
4 tinyscheme    78 152 po strip
       
5 lua5.1   174 976 standardní instalace z balíčku
6 lua5.2   195 416 standardní instalace z balíčku
7 luajit   445 080 standardní instalace z balíčku
8 python2.7 3 674 216 standardní instalace z balíčku
9 python3.8 5 490 488 standardní instalace z balíčku

Binární kód Femtolispu byl zmenšen příkazem strip, a to z této původní velikosti:

$ ls -l flisp
 
-rwxrwxr-x 1 ptisnovs ptisnovs 205336 Dec 11 11:10 flisp

Na zobrazených přibližně 176 kB:

$ strip flisp
$ ls -l flisp
 
-rwxrwxr-x 1 ptisnovs ptisnovs 176296 Dec 11 13:10 flisp
Poznámka: do určité míry se jedná o porovnání hrušek s jablky, protože nebereme do úvahy, jaké funkce jsou danou implementací poskytovány ani případnou závislost na podpůrných knihovnách. Ovšem všechny výše uvedené jazyky podporují REPL (Read Eval Print Loop), jsou dynamicky typované, podporují do jisté míry funkcionální programování a navíc mají automatického správce paměti: takže se opravdu může jednat o porovnání hrušek s jablky a nikoli hrušek s tanky.
Poznámka2: některé další možnosti, například běh LISPu či Scheme na mikrořadičích, jsou zmíněny na stránce https://dmitryfrank.com/ar­ticles/lisp_on_mcu.

7. Vylepšení REPLu jazyka Femtolisp

Femtolisp není přeložen s podporou knihovny readline, což je patrné i z následujícího výpisu dynamických knihoven, na kterých Femtolisp závisí:

$ ldd flisp 
 
        linux-vdso.so.1 (0x00007ffd68cb3000)
        libm.so.6 =→ /lib/x86_64-linux-gnu/libm.so.6 (0x00007f36b36d4000)
        libc.so.6 =→ /lib/x86_64-linux-gnu/libc.so.6 (0x00007f36b34e2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f36b3869000)

Proč je to důležité? Nepodpora readline, mj. znamená, že neexistuje historie příkazového řádku, není možné používat editační příkazy typu Ctrl+A, Ctrl+E, vyhledávání v dříve zadaných příkazech pomocí Ctrl+R atd. A navíc nefunguje automatické doplňování jmen symbolů klávesou Tab. Tyto vlastnosti, které dnes od REPLů prakticky automaticky očekáváme, je možné do jisté míry doplnit externím nástrojem rlwrap. Tomu můžeme předat soubor se symboly pro automatické doplňování. Spustíme tedy flisp a zavoláme funkci environment:

> (environment)
 
(zero? write wchar void vector.map vector->list vector.alloc vector? values
       untrace vector ulong uint64 uint32 typeof uint16 uint8 traced? trace
       truncate top-level-exception-handler top-level-value to-proper
       time.string that table.values table.pairs table.keys table.invert
       table.foreach table.clone table.foldl table? table tan time.fromstring
       ...
       ...
       ...

Tento seznam symbolů je možné přesměrovat do souboru, který se může jmenovat například environment.txt. Jeho ukázku nalezneme na adrese https://github.com/tisnik/lisp-families/blob/master/femto­lisp/environment.txt. Následně flisp ukončíme a spustíme odlišným způsobem:

$ rlwrap -f environment.txt -m -M .scm ./flisp

Zdánlivě nedojde k žádné podstatné změně, ovšem nyní je možné využívat historii příkazového řádku (šipky nahoru, dolů + vyhledávání), editovat obsah příkazového řádku, zavolat externí editor pro delší texty a taktéž používat klávesu Tab pro doplňování jmen symbolů – tedy v naprosté většině případů funkcí, maker a speciálních forem programovacího jazyka.

Poznámka: soubor environment.txt lze přepsat ve chvíli, kdy je do REPLu načten program funkcí (load jméno_souboru). V takovém případě se ve výsledném souboru objeví i symboly definované v programu. Nejedná se sice o plnohodnotnou formu technologie code completion, ovšem v každém případě bude situace lepší, než nemít k dispozici žádnou podobnou pomůcku.

V dalším textu jsou vypsány vybrané klávesové zkratky, které jsou ve výchozím nastavení použity knihovnou GNU Readline při přepnutí do režimu Emacs (což je výchozí chování).

Příkazy pro přesuny kurzoru

Základní příkazy pro přesun kurzoru používají kombinaci Ctrl+znak, Alt+znak popř. alternativně Esc, znak v případě, že zkratky Alt+znak kolidují s emulátorem terminálu (například vyvolávají příkazy z menu – což je z nějakého důvodu dnes moderní). Pokud je terminál správně nakonfigurován, měly by fungovat i kurzorové šipky a navíc i klávesy Home a End (se zřejmou funkcí):

Klávesa Význam
Ctrl+B přesun na předchozí znak
Ctrl+F přesun na další znak
   
Alt+B přesun na předchozí slovo
Alt+F přesun na další slovo
Esc, B shodné s Alt+B
Esc, F shodné s Alt+F
   
Ctrl+A přesun na začátek řádku
Ctrl+E přesun na konec řádku

Mazání textu, práce s kill ringem

Pro přesun části textu v rámci editovaného řádku se používá takzvaný kill ring, do něhož se smazaný text uloží. Pro vložení takto smazaného textu do jiné oblasti se používá operace nazvaná yank (odpovídá paste). Některé dále uvedené příkazy dokážou s kill ringem pracovat:

Klávesa Význam
Ctrl+K smaže text od kurzoru do konce řádku a uloží ho do kill ringu
Ctrl+U smaže text od začátku řádku do pozice kurzoru a uloží ho do kill ringu
Ctrl+W smaže předchozí slovo a uloží ho do kill ringu
Alt+D smaže následující slovo a uloží ho do kill ringu
   
Ctrl+Y vloží text z kill ringu na místo, na němž se nachází kurzor (yank)
Alt+Y po operaci Ctrl+Y dokáže rotovat historií kill ringu a obnovit tak (před)předchozí smazaný text
   
Ctrl+D smaže jeden znak (pokud je ovšem na řádku nějaký obsah, jinak typicky ukončí aplikaci)

Práce s historií dříve zadaných příkazů

Klávesa Význam
Ctrl+P průchod historií – předchozí text
Ctrl+N průchod historií – následující text
Ctrl+R zpětné (interaktivní) vyhledávání v historii
Ctrl+G ukončení režimu vyhledávání

Některé další dostupné příkazy

Klávesa Význam
Tab implicitní klávesa pro zavolání completeru
Ctrl+T prohození dvou znaků (před kurzorem a na pozici kurzoru)
Ctrl+^ zavolání externího editoru
   
Alt+U text od pozice kurzoru do konce slova se změní NA VERZÁLKY
Alt+L text od pozice kurzoru do konce slova se změní na mínusky
Alt+C text od pozice kurzoru do konce slova se změní Tak, Že Slova Začínají Velkým Písmenem

Důležitá i klávesová zkratka Ctrl+^, která zavolá textový editor specifikovaný v proměnné prostředí EDITOR nebo VISUAL. Do editoru lze vložit delší funkci či makro a uložit výsledek, který se v REPLu ihned provede. Při volání rlwrap jsme nastavili jména dočasných souborů tak, aby měly příponu .scm, což zvolenému editoru umožní zvýraznění syntaxe.

8. Základní vlastnosti jazyka Femtolisp

Femtolisp sice ve svém názvu obsahuje LISP, ale samotná sémantika implementovaného jazyka se spíše přibližuje vlastnostem popsaným v R4RS i R5RS, takže jen v krátkosti (většinu příkladů jsme již viděli v některém z předchozích článků). Všechny ukázky jsou zkopírovány přímo z REPLu.

V dále uvedených příkladech budeme používat upravenou formu funkce print, která provede automatické odřádkování:

(define (print item)
     (princ item)
     (newline))
Poznámka: každá funkce vrací nějakou hodnotu, a to včetně funkce newline vracející #t (true). Pokud vám nevyhovuje neustálý výpis této hodnoty, lze funkci print upravit na:
(define (print item)
     (princ item)
     (newline)
     "")

Práce s tečka-dvojicemi

Název LISP sice vznikl ze slov LISt Processing, ovšem ve skutečnosti není základním složeným typem LISPů seznam (list), ale takzvaná tečka-dvojice. Seznamy jsou jen jednou formou uspořádání tečka dvojic (další formou mohou být stromy atd.).

(print '(1 . 2))
(1 . 2)
 
(print '(1 . ((2 . 3) . 4)))
(1 (2 . 3) . 4)
 
(print '((1 . 2) . (3 . 4)))
((1 . 2) 3 . 4)
 
; this is NOT proper list
(print '(1 . (2 . (3 . nil))))
(1 2 3 . nil)
 
; this is proper list
(print '(1 . (2 . (3 . ()))))
(1 2 3)
 
; this is NOT proper list
(print '(1 . (2 . (3 . (4 ())))))
(1 2 3 4 ())
 
; this is proper list
(print '(1 . (2 . (3 . (4 . ())))))
(1 2 3 4)

Konstrukce tečka dvojic realizovaná formou cons

Tečka-dvojice lze z existujících hodnot a symbolů konstruovat s využitím formy cons:

; cons usage
(cons 1 2)
(1 . 2)
 
; another cons usage
(cons 1 (cons 2 3))
(1 2 . 3)
 
; this is proper list
(cons 1 (cons 2 (cons 3 '())))
(1 2 3)
 
; this is proper list
(cons 1 '(2 3 4))
(1 2 3 4)
 
; this is NOT proper list
(cons 1 (cons 2 (cons 3 4)))
(1 2 3 . 4)

Konstrukce seznamů

Z tečka-dvojic lze sestrojit seznamy, což bylo ukázáno v posledním příkladu:

; this is proper list
(print '(1 . (2 . (3 . (4 . ())))))
(1 2 3 4)

Vzhledem k tomu, že se seznamy používají velmi často (a to i pro vytváření vyhodnocovaných forem), existuje i kratší způsob jejich zápisu:

; empty list
'()
()
 
; a list
'(1 2 3 4)
(1 2 3 4)
 
; another list
(list 1 2 3 4)
(1 2 3 4)

Základní operace se seznamy – car a cdr

Ze seznamů lze získat první prvek formou car a zbylé prvky formou cdr. Existují i další kombinace car a cdr zapisované jako cadr, cddr atd.:

; create list and assign it to symbol
(define a '(1 2 3 4))
(1 2 3 4)
 
; get the first item
(car a)
1
 
; get the rest of a list
(cdr a)
(2 3 4)
 
; combination of car+cdr
(cadr a)
2
 
; combination of cdr+cdr
(cddr a)
(3 4)

9. Funkce a speciální formy

Podobně jako u každého dialektu programovacího jazyka LISP resp. Scheme, i v případě Femtolispu se program skládá především z funkcí. Ty mohou být anonymní (nepojmenované) či naopak pojmenované. Nejprve se zabývejme pojmenovanými funkcemi, protože ty se chovají prakticky stejně, jako běžné funkce v jiných programovacích jazycích – pouze způsob jejich zápisu je odlišný. Pojmenované funkce se definují pomocí speciální formy define, za níž v závorkách následuje jméno funkce. Každá funkce může mít libovolný počet parametrů, jejichž jména se uvádí v seznamu ihned za pojmenováním funkce. Poslední částí formy define je v tomto případě tělo funkce, přičemž po zavolání funkce se vyhodnocená forma vrátí jako její výsledek (nikde se tedy nezapisuje slovo „return“ ani nic s podobným významem – ostatně podobný způsob je použit i v Rustu):

; one-liner function
(define (add x y) (+ x y))
 
; function written on more lines
(define (mul x y)
  (* x y))
Poznámka: ve skutečnosti je výše uvedená definice pouze syntaktickým cukrem nahrazujícím definici proměnné, jejíž hodnotou je anonymní funkce, která je zapisovaná pomocí speciální formy lambda. Bez použití syntaktického cukru by definice nové funkce vypadala takto:
; function written on more lines using lambda
(define div (lambda (x y)
  (* x y)))

Zavolání funkce je jednoduché – používá se stále ten samý formát seznamu, na jehož prvním místě je jméno funkce a za ním následují parametry:

(print (add 1 2))
(print (mul 6 7))
(print (div 10 3))

Kromě pojmenovaných funkcí, které jsme si již představili v předchozím textu, je možné ve Femtolispu použít i funkce anonymní, tj. funkce, které nejsou navázány na žádné jméno. Pro tento účel se používá přímo lambda výraz (bez define), podobně jako v každém ortodoxním Lispu (snad kromě PicoLispu):

; anonymous function is a value
(lambda (x y) (+ x y))
 
; call anonymous function
(print (lambda (x y) (+ x y)))

Další důležitou vlastností jazyka implementovaného ve Femtolispu, s níž se dnes (znovu) seznámíme, je použití takzvaných speciálních forem. Ze syntaktického hlediska jsou speciální formy zapisovány naprosto stejným způsobem jako běžné funkce, ovšem existuje zde jeden významný rozdíl – zatímco u funkcí jsou všechny jejich parametry nejdříve vyhodnoceny, u speciálních forem k tomuto vyhodnocení obecně nedochází, resp. jsou vyhodnoceny pouze některé parametry (které konkrétně, to závisí na tom, o jakou speciální formu se jedná). S některými speciálními formami jsme se již setkali, především s formou define či let, ovšem existují i formy další – cond, if, and, lambda, quote, do atd.

Speciální forma cond:

(define (sgn n)
  (cond
        ((< n 0)      'negative)
        ((> n 0)      'positive)
        ((zero? n)    'zero)))

Alternativní forma s větví else:

(define (sgn-2 n)
  (cond
        ((< n 0)      'negative)
        ((> n 0)      'positive)
        (#t           'zero)))

Speciální forma case:

(print
    (case (* 2 3)
      ((2 3 5 7) 'prime)
      ((1 4 6 8 9) 'composite)))
(print
    (case (car '(a y x))
    ((a e i o u) 'vowel)
    ((w y) 'semivowel)
    (else 'consonant)))

Speciální forma do pro realizaci smyček:

(define (compute-pi n)
  (let ((pi 4.0))
    (do ((i 3 (+ i 2)))
      ((> i (+ n 2)))
      (set! pi (* pi (/ (- i 1) i) (/ (+ i 1) i))))
    pi))
 
(do ((n 1 (* n 2)))
  ((> n 10000000))
  (princ n)
  (princ " ")
  (princ (compute-pi n))
  (newline))

Pojmenované let, taktéž pro realizaci smyček:

(define (let-loop)
  (let loop ((i 0))
    (cond ((> i 10))
          (else (print i)
                (loop (+ i 1))))))

Smyčka typu repeat n:

(define (call-n-times n proc)
  (let loop ((n n))
    (unless (zero? n)
      (proc)
      (loop (- n 1)))))
 
(define (print-hello)
  (print "Hello"))
 
(call-n-times 10 print-hello)

Ještě lepší řešení pro funkci s argumenty:

(define (call-n-times n proc argument)
  (let loop ((n n))
    (unless (zero? n)
      (proc argument)
      (loop (- n 1)))))
 
(call-n-times 10 print "Hello")

10. Pojmenované funkce s proměnným počtem parametrů

Vzhledem k tomu, že speciální formu define (ve variantě, kdy se definuje funkce) lze kdykoli zapsat s využitím speciální formy lambda, je v programovacím jazyku Femtolisp možné nadefinovat pojmenovanou funkci akceptující proměnný (tj. v krajním případě i nulový) počet parametrů, z nichž je při volání funkce automaticky vytvořen seznam, se kterým je možné v těle funkce libovolným způsobem manipulovat. Syntakticky vypadá definice takové funkce následovně:

(define (jméno funkce . parametr) [tělo funkce])

Což je ekvivalentní zápisu, který již známe z předchozího textu:

(define jméno funkce (lambda parametr [tělo funkce]))
Poznámka: v předchozím zápisu je důležité, že parametr není uzavřen do kulatých závorek tak, jak by tomu bylo v případě, kdyby se jednalo o klasický seznam parametrů.

Následuje příklad definice funkce s proměnným počtem parametrů:

; funkce vracející počet skutečně předaných parametrů
(define (foo . parametry) (length parametry))

Zavolání této funkce bez parametrů vrátí nulu:

(foo)
0

Předat můžeme jeden parametr:

(foo 42)
1

A samozřejmě i větší počet parametrů:

(foo 1 2)
2
 
(foo "bar" "baz")
2
 
(foo '(1 2 3 4))
1
Poznámka: v posledním příkladu byl předán jediný parametr (kterým je čistě náhodou seznam), proto se vrátila jednička.

Ukažme si ještě alternativní formu zápisu využívající kombinace define a lambda:

; alternativní forma zápisu
(define foo (lambda parametry (length parametry)))
 
; volání funkce bez parametrů
(foo)
0
 
; volání funkce se třemi parametry (zde se jedná o trojici symbolů)
(foo 'a 'b 'c)
3

11. Povinné a nepovinné parametry pojmenovaných funkcí

Při definici funkcí lze určit i nepovinné parametry. Hodnoty nepovinných parametrů se uloží do seznamu, jehož jméno je uvedeno za tečkou v seznamu parametrů. Jedná se tedy o kombinaci klasických funkcí s konstantním počtem povinných parametrů a funkcí s proměnným počtem parametrů.

Podívejme se na jednoduchý příklad funkcí, které se liší jak počtem parametrů, tak i tím, zda akceptují nepovinné parametry:

(define (f1)
  (print "no parameters"))
 
(define (f2 a)
  (print "one parameter")
  (print a))
 
(define (f3 a b)
  (print "two parameters")
  (print a)
  (print b))
 
(define (f4 a . b)
  (print "at least one parameter")
  (print a)
  (print b))
 
(define (f5 a b . c)
  (print "at least two parameters")
  (print a)
  (print b)
  (print c))
 
(f1)
(f2 10)
(f3 1 2)
(f4 1)
(f4 1 2)
(f4 1 2 3)
(f5 1 2)
(f5 1 2 3)
(f5 1 2 3 4)

Výsledky získané po spuštění skriptu:

(f1)
no parameters
 
(f2 10)
one parameter
10
 
(f3 1 2)
two parameters
1
2
 
(f4 1)
at least one parameter
1
()
 
(f4 1 2)
at least one parameter
1
(2)
 
(f4 1 2 3)
at least one parameter
1
(2 3)
 
(f5 1 2)
at least two parameters
1
2
()
 
(f5 1 2 3)
at least two parameters
1
2
(3)
 
(f5 1 2 3 4)
at least two parameters
1
2
(3 4)

12. Koncová rekurze

V naprosté většině algoritmů se objevují bloky kódu, které se mají iterativně opakovat. Při programování s využitím funkcionálního paradigmatu se iterace vyjadřuje formou rekurze. Ta je samozřejmě ve Scheme podporována (mezi jediné známější jazyky, které rekurzi nepodporovaly, patřil původní FORTRAN a Basic), ovšem specifikace jazyka Scheme jde ještě dále, protože určuje, ve kterých případech je skutečná rekurze (při níž se parametry a návratové adresy musí ukládat na zásobník) nahrazena takzvanou koncovou rekurzí, což zjednodušeně řečeno znamená, že se namísto skutečného rekurzivního volání funkce interně provede obyčejný skok (koncový skok či koncové volání) bez nutnosti alokace místa na zásobníku pro parametry volané funkce a návratové adresy. Touto specifikací se také do značné míry řídí Femtolisp.

Koncová rekurze představuje při správném použití velmi silnou programovací techniku, protože umožňuje zapisovat mnoho algoritmů v mnohdy elegantní rekurzivní formě, ovšem skutečné zpracování takto zapsaných algoritmů je stejně efektivní jako provádění programové smyčky (každou koncovou rekurzi lze nahradit smyčkou a naopak).

Následující funkce plus sice rekurzivně volá sebe sama, ovšem z pohledu sémantiky se jedná o běžnou iteraci, protože volání plus lze nahradit skokem – není zapotřebí si pamatovat předchozí výsledky:

; A classic example taken from MIT 6.001 course
 
(define (plus x y)
  (if (= x 0)
      y
      (plus (- x 1) (+ y 1))))
 
(princ (plus 10000000 10000000))
(newline)

Při nepatrné úpravě ovšem získáme rekurzivní variantu, v níž je nutné si pamatovat mezivýsledky získané při fázi navíjení:

; A classic example taken from MIT 6.001 course
 
(define (plus x y)
  (if (= x 0)
      y
      (+ 1 (plus (- x 1) y))))
 
(princ (plus 10000000 10000000))
(newline)

Dalším klasickým příkladem rozdílu mezi normální (plnou, skutečnou) rekurzí a koncovou rekurzí je výpočet faktoriálu. Ten můžeme zapsat mnoha způsoby, například (jak je to v matematice obvyklé), rekurzivně:

(define (factorial n)
    (if (= n 0) ; podmínka pro ukončení rekurzivního zanořování
        1       ; faktoriál nuly je definitoricky roven jedné
        (* n (factorial (- n 1)))))

Z teoretického hlediska není na výše uvedené funkci nic nekorektního, ovšem při jejím praktickém používání brzy narazíme na limit způsobený omezenou velikostí zásobníku.

Výše uvedený rekurzivní výpočet lze relativně malou úpravou převést na výpočet který (alespoň v programovacím jazyce Scheme) vede na koncové volání, což mj. znamená, že paměťové (prostorové) nároky tohoto programu jsou konstantní:

; výpočet faktoriálu využívající koncového volání
(define (factorial n)
    (let fact-iter (          ; pomocná vnitřní funkce
                  (n n)       ; počitadlo iterací
                  (result 1)) ; průběžný výsledek
        (if (= n 0)           ; po dosažení koncového stavu
            result            ; se vrátí průběžný výsledek
            (fact-iter (- n 1) (* n result)) ; koncové volání
        )))
Poznámka: i překlad do nativního kódu by měl být v tomto případě lepší, než u běžné rekurzivní varianty.

Zásobník používaný v rekurzivních variantách není nijak omezený (na rozdíl od mnoha dalších programovacích jazyků). Takže se může stát, že proces začne používat swap. Prozatím ve Femtolispu neexistuje možnost omezení velikosti zásobníku (na daný počet prvků) tak, jak to má například Guile:

(define (plus x y)
  (if (= x 0)
      y
      (plus (- x 1) (+ y 1))))
 
(define (test)
  (display (plus 10000000 10000000)))
 
(define (handler)
  (display "Stack overflow\n"))
 
(call-with-stack-overflow-handler 1000 test handler)

13. Typový systém Femtolispu

Femtolisp je sice odvozen od programovacího jazyka Scheme, ale ve skutečnosti postrádá například plnou „numerickou věž“, což znamená, že zde neexistuje úplná hierarchie numerických datových typů (celá čísla, zlomky, reálná čísla, komplexní čísla). Většina aritmetických operací je prováděna s hodnotami s plovoucí řádovou čárkou zpracovatelnými matematickým koprocesorem popř. se operace provádí s čísly typu int. To mj. znamená, že se Femtolisp bude chovat odlišně, než například Guile. Příkladem může být jednoduchý výpočet podílu.

Femtolisp:

(/ 4 3)
1.3333333333333333

Guile:

(/ 4 3)
4/3

Test na přetečení celých čísel:

(define (print item)
     (princ item)
     (newline))
 
(do ((n 1 (* n 2)))
  ((> n 100000000000000000000))
  (print n))

Po spuštění ve Femtolispu je patrné, že se korektně detekovalo přetečení:

1
2
4
8
16
32
...
...
...
72057594037927936
144115188075855872
288230376151711744
576460752303423488
 
Press ENTER or type command to continue
parse-error: read: overflow in numeric constant 100000000000000000000
in file int_size.scm
Poznámka: mnoho dalších implementací LISPu a Scheme by přešlo na reprezentaci celých čísel s neomezeným rozsahem.

Podívejme se nyní na další datové typy a jejich hodnoty. Snadno zjistíme, že datový typ (a současně i hodnota) nil není přímo podporován – i v tomto ohledu se tedy blížíme spíše ke Scheme než ke klasickým LISPům:

nil
eval: variable nil has no value
#0 (lambda)

Pro reprezentaci pravdivostních hodnot se používají symboly #t a #f, které se vyhodnocují samy na sebe:

#t
#t
 
#f
#f

Specifický význam má i prázdný seznam, jenž je zapisován takto:

'()
()

Nebo takto:

()
()
Poznámka: vzhledem k tomu, že neexistuje symbol nil, není nutné definovat podmínky jeho ekvivalence s prázdným seznamem, což sice skalní LISPaře nepotěší, ale jedná se o čistší návrh.

Podporovány jsou pochopitelně seznamy, ovšem vzhledem k tomu, že jak seznamy, tak i formy se zapisují do hranatých závorek, je u seznamů nutné zakázat jejich vyhodnocování:

(1 2 3)
type error: apply: expected function, got 1
#0 (lambda)
 
'(1 2 3)
(1 2 3)

Femtolisp podporuje i zápis vektorů, resp. přesněji řečeno literálů představujících vektory:

[1 2 3]
[1 2 3]

Řetězce se zapisují do uvozovek, jak je to běžné.

Ve Femtolispu je možné typ hodnoty (popř. skupinu typů) zjistit s využitím několika predikátů, což jsou formy, jejichž jména končí otazníkem:

Predikát
atom?
list?
vector?
null?
number?
fixnum?

Tyto predikáty si můžeme relativně snadno otestovat, a to pro hodnoty libovolného typu:

(define (print item)
     (princ item)
     (newline))
 
(define nil '())
 
(print "atom?")
(print (atom? nil))
(print (atom? #t))
(print (atom? 42))
(print (atom? 3.14))
(print (atom? "string"))
(print (atom? '(1 2 3)))
(print (atom? [1 2 3]))
(newline)
 
(print "list?")
(print (list? nil))
(print (list? #t))
(print (list? 42))
(print (list? 3.14))
(print (list? "string"))
(print (list? '(1 2 3)))
(print (list? [1 2 3]))
(newline)
 
(print "vector?")
(print (vector? nil))
(print (vector? #t))
(print (vector? 42))
(print (vector? 3.14))
(print (vector? "string"))
(print (vector? '(1 2 3)))
(print (vector? [1 2 3]))
(newline)
 
(print "null?")
(print (null? nil))
(print (null? #t))
(print (null? 42))
(print (null? 3.14))
(print (null? "string"))
(print (null? '(1 2 3)))
(print (null? [1 2 3]))
(newline)
 
(print "number?")
(print (number? nil))
(print (number? #t))
(print (number? 42))
(print (number? 3.14))
(print (number? "string"))
(print (number? '(1 2 3)))
(print (number? [1 2 3]))
(newline)
 
(print "fixnum?")
(print (fixnum? nil))
(print (fixnum? #t))
(print (fixnum? 42))
(print (fixnum? 3.14))
(print (fixnum? "string"))
(print (fixnum? '(1 2 3)))
(print (fixnum? [1 2 3]))
(newline)
 
(print "zero?")
(print (zero? 0))
(print (zero? 42))
(newline)

Výsledky jsou vypsány na jednotlivé řádky, což ovšem není příliš přehledné:

atom?
#t
#t
#t
#t
#t
#f
#t
 
list?
#t
#f
#f
#f
#f
#t
#f
 
vector?
#f
#f
#f
#f
#f
#f
#t
 
null?
#t
#f
#f
#f
#f
#f
#f
 
number?
#f
#f
#t
#t
#f
#f
#f
 
fixnum?
#f
#f
#t
#f
#f
#f
#f
 
zero?
#t
#f

Přehlednější je výpis v tabulkovém formátu:

Hodnota atom? list? vector? null? number? fixnum?
'() #t #t #f #t #f #f
#t #t #f #f #f #f #f
42 #t #f #f #f #t #t
3.14 #t #f #f #f #t #f
„string“ #t #f #f #f #f #f
'(1 2 3) #f #t #f #f #f #f
[1 2 3] #t #f #t #f #f #f

14. Lokální rozsah proměnných

Jazyk Scheme (do kterého Femtolisp spadá, i přes své jméno) je, na rozdíl od původních LISPů, založen na lokálním rozsahu proměnných (local scope). Můžeme si to ostatně relativně snadno ukázat na následujícím demonstračním příkladu, v němž je uvnitř funkce add použit lokální rozsah, v rámci něhož je vyhodnocována proměnná x:

(define x 1)
(define y 2)
 
(define (add x y)
    ; rozsah (scope) je lokální!
    (set! x (+ x y))
    x)
 
(print (add x y))
(print (add x y))
 
(set! x 10)
(print (add x y))
(print (add x y))

Po spuštění tohoto příkladu se vypíše:

3
3
12
12
Poznámka: ve funkci add se tedy z pohledu z vnějšku neměnila globální proměnná x.

Příklad s globálními a lokálními proměnnými:

Příklad s globálními a lokálními proměnnými:

(define x 1)
(define y 2)
 
(define (add x y)
    (+ x y))
 
(print (add x y))
 
(print
    (let ((x 10)
          (y 20))
          (add x y)))
 
 
(set! x 10)
(print (add x y))
 
(print
    (let ((x 10)
          (y 20))
          (add x y)))
 
(print
    (let ((x 100))
          (add x y)))

Po spuštění tohoto demonstračníh příkladu se vypíše:

3
30
12
30
102
Poznámka: lexical scope má ovšem dalekosáhlejší důsledky, které mj. ovlivňují činnost správce paměti atd. Jde o to, že pokud je nějaká proměnná (která je definovaná vně funkce) na funkci navázána (prakticky: je ve funkci použita), nemůže tato proměnná zaniknout ani při opuštění daného bloku, protože společně s funkcí tvoří takzvaný uzávěr (closure). S uzávěry se v LISPovské rodině jazyků setkáme velmi často a dnes je nalezneme i v některých dalších programovacích jazycích (zdaleka ne ve všech):
(define (larger-than limit)
    (lambda (value) (> value limit)))
 
(print ((larger-than 5) 0))
(print ((larger-than 5) 10))
 
(print (filter (larger-than 5) '(1 2 3 4 5 6 7 8 9 10)))

S těmito výsledky:

#f
#t
(6 7 8 9 10)
(6 7 8 9 10)

Další, nepatrně složitější implementace uzávěrů:

(define counter
    (let ((i -1))
         (lambda ()
             (set! i (+ i 1))
             i)))
 
(print (counter))
(print (counter))
(print (counter))

S výsledky:

0
1
2
Poznámka: zde jsme vytvořili funkci counter, kterou lze v určitém ohledu považovat za objekt, protože má vlastní stav a zapouzdřuje hodnotu čítače představovaného proměnnou i.
(define (get-counter)
    (let ((i -1))
         (lambda ()
             (set! i (+ i 1))
             i)))
 
(define counter1 (get-counter))
(define counter2 (get-counter))
 
(print (counter1))
(print (counter1))
(print (counter1))
 
(print (counter2))
(print (counter2))
(print (counter2))
 
(print (counter1))
(print (counter1))
(print (counter1))

Výsledky činnosti dvou čítačů:

0
1
2
 
0
1
2
 
3
4
5

Uzávěry ve skutečnosti nejsou „obyčejnými“ funkcemi, protože je lze současně považovat za úložiště dat. Viz například následující příklad, který je uváděn ve slavném kurzu 6.001 na MIT (pravděpodobně nejlépe strukturovaném kurzu o informatice vůbec). V tomto příkladu je cons- nositelem dat o tečka-dvojici:

(define (cons- x y)
  (lambda (m)
    (if (= m 0) x y)))
 
(define (car- z) (z 0))
(define (cdr- z) (z 1))
 
(princ (cons- 1 2))
(newline)
 
(princ (car- (cons- 1 2)))
(newline)
 
(princ (cdr- (cons- 1 2)))
(newline)
Poznámka: jazyky podporující uzávěry tedy teoreticky vůbec nemusí podporovat další způsoby reprezentace dat (i když z praktického pohledu je tomu jinak).

15. Makrosystém

Ve Femtolispu jsou plně podporována i makra, která částečně vychází ze systému maker Common Lispu. S makry souvisí i použití znaků nazývaných quote a quasiquote, které umožňují ve fázi expanze maker vkládání hodnot či symbolů do expandované části kódu. Jen ve stručnosti si ukažme použití quote a quasiquote (nejenom) při konstrukci seznamů:

(define b (list 1 2 3))
 
(print "quote:")
(print '(a b c))
(print '(a ,b c))
(print '(a ,@b c))
(newline)
 
(print "quasiquote:")
(print `(a b c))
(print `(a ,b c))
(print `(a ,@b c))
(newline)

Z výsledků je patrné, jak znaky „`“, „,“ a „,@“ ovlivňují expanzi prvků v seznamu. To neplatí pro klasický znak „'“ (quote), který zcela zakazuje vyhodnocování prvků v seznamu (první tři výsledky):

quote:
(a b c)
(a ,b c)
(a ,@b c)
 
quasiquote:
(a b c)
(a (1 2 3) c)
(a 1 2 3 c)

Následuje příklad makra s implementací programové smyčky typu while. Povšimněte si, že se v makru skutečně musí použít quasiquote, uvnitř quasiquote pak „,symbol“ a „,@symbol“:

(define-macro (while- test . forms)
  `((label -loop- (lambda ()
                    (if ,test
                        (begin ,@forms
                               (-loop-))
                      ())))))
 
(define (test-while)
  (set! i 0)
  (while (< i 10000000) (set! i (+ i 1)))
  (princ i)
  (newline))

16. Reálné použití Femtolispu

Femtolisp, pokud by byl používán samostatně jako jeden z dialektů LISPu resp. Scheme, ve skutečnosti nepřináší žádné nové myšlenky a pro praktické použití je (alespoň podle mého názoru) lepší použít jinou implementaci – Guile (snadná vestavitelnost), Chicken Scheme (kvalitní překladač), Racket (prakticky zaměřeno, podpora dalších (meta)jazyků) či Common Lisp (podle toho, co je konkrétně od implementace jazyka vyžadováno). Ovšem Femtolisp zabudovaný přímo v jazyce Julia otevírá zcela nové možnosti například při testování nových syntaktických prvků, transformacích kódu před jeho dalším zpracováním, dokonce i testováním nových typových systémů atd.

17. Repositář s demonstračními příklady

Zdrojové kódy všech dnes použitých demonstračních příkladů určených pro spuštění ve Femtolispu 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:

Root obecny

# Příklad Popis příkladu Cesta
1 boolean_ops.scm pravdivostní operace https://github.com/tisnik/lisp-families/blob/master/femto­lisp/boolean_ops.scm
2 case1.scm speciální forma case https://github.com/tisnik/lisp-families/blob/master/femto­lisp/case1.scm
3 case2.scm speciální forma case https://github.com/tisnik/lisp-families/blob/master/femto­lisp/case2.scm
4 closure1.scm uzávěry, příklad číslo 1 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/closure1.scm
5 closure2.scm uzávěry, příklad číslo 2 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/closure2.scm
6 closure3.scm uzávěry, příklad číslo 3 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/closure3.scm
7 closure4.scm uzávěry, příklad číslo 4 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/closure4.scm
8 cond2.scm speciální forma cond https://github.com/tisnik/lisp-families/blob/master/femto­lisp/cond2.scm
9 cond.scm speciální forma cond https://github.com/tisnik/lisp-families/blob/master/femto­lisp/cond.scm
10 cons.scm funkce cons použitá pro konstrukci seznamu https://github.com/tisnik/lisp-families/blob/master/femto­lisp/cons.scm
11 dot_pairs.scm konstrukce tečka dvojic (dot pairs) https://github.com/tisnik/lisp-families/blob/master/femto­lisp/dot_pairs.scm
12 factorial1.scm rekurzivní výpočet faktoriálu, první varianta https://github.com/tisnik/lisp-families/blob/master/femto­lisp/factorial1.scm
13 factorial2.scm rekurzivní výpočet faktoriálu, druhá varianta https://github.com/tisnik/lisp-families/blob/master/femto­lisp/factorial2.scm
14 factorial3.scm tail rekurze při výpočtu faktoriálu https://github.com/tisnik/lisp-families/blob/master/femto­lisp/factorial3.scm
15 factorial4.scm tabulka faktoriálů https://github.com/tisnik/lisp-families/blob/master/femto­lisp/factorial4.scm
16 functions.scm deklarace a volání funkcí https://github.com/tisnik/lisp-families/blob/master/femto­lisp/functions.scm
17 int_size.scm rozsah hodnot typu integer https://github.com/tisnik/lisp-families/blob/master/femto­lisp/int_size.scm
18 lexical_scope1.scm lexikální oblast platnosti proměnných, příklad číslo 1 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lexical_scope1.scm
19 lexical_scope2.scm lexikální oblast platnosti proměnných, příklad číslo 2 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lexical_scope2.scm
20 lexical_scope3.scm lexikální oblast platnosti proměnných, příklad číslo 3 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lexical_scope3.scm
21 lexical_scope4.scm lexikální oblast platnosti proměnných, příklad číslo 4 https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lexical_scope4.scm
22 lists.scm základní práce se seznamy https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lists.scm
23 pi1.scm výpočet π realizované ve Scheme, základní varianta https://github.com/tisnik/lisp-families/blob/master/femto­lisp/pi1.scm
24 predicates.scm základní predikáty https://github.com/tisnik/lisp-families/blob/master/femto­lisp/predicates.scm
25 ackermann.scm výpočet Ackermannovy funkce https://github.com/tisnik/lisp-families/blob/master/femto­lisp/ackermann.scm
26 functions_varargs.scm https://github.com/tisnik/lisp-families/blob/master/femto­lisp/functions_varargs.scm
27 lambdas.scm lambda výrazy https://github.com/tisnik/lisp-families/blob/master/femto­lisp/lambdas.scm
28 let_loop_iterate1.scm pojmenovaná forma let https://github.com/tisnik/lisp-families/blob/master/femto­lisp/let_loop_iterate1.scm
29 let_loop_iterate2.scm pojmenovaná forma let https://github.com/tisnik/lisp-families/blob/master/femto­lisp/let_loop_iterate2.scm
30 let_loop.scm pojmenovaná forma let https://github.com/tisnik/lisp-families/blob/master/femto­lisp/let_loop.scm
31 MIT6.001_plus1.scm funkce plus, iterativní výpočet https://github.com/tisnik/lisp-families/blob/master/femto­lisp/MIT6.001_plus1.scm
32 MIT6.001_plus2.scm funkce plus, rekurzivní výpočet https://github.com/tisnik/lisp-families/blob/master/femto­lisp/MIT6.001_plus2.scm
33 MIT6.001_sqrt.scm funkce sqrt https://github.com/tisnik/lisp-families/blob/master/femto­lisp/MIT6.001_sqrt.scm

18. Předchozí části seriálu

V této kapitole jsou uvedeny odkazy na všechny předchozí části seriálu o světě programovacích jazyků LISP a Scheme (kromě samostatného seriálu, který se věnoval programovacímu jazyku Clojure):

  1. Jemný úvod do rozsáhlého světa jazyků LISP a Scheme
    https://www.root.cz/clanky/jemny-uvod-do-rozsahleho-sveta-jazyku-lisp-a-scheme/
  2. PicoLisp: minimalistický a přitom překvapivě výkonný interpret Lispu
    https://www.root.cz/clanky/picolisp-minimalisticky-a-pritom-prekvapive-vykonny-interpret-lispu/
  3. PicoLisp: užitečné funkce a speciální formy používané při tvorbě aplikací
    https://www.root.cz/clanky/picolisp-uzitecne-funkce-a-specialni-formy-pouzivane-pri-tvorbe-aplikaci/
  4. PicoLisp: dokončení popisu a několik praktických rad na závěr
    https://www.root.cz/clanky/picolisp-dokonceni-popisu-a-nekolik-praktickych-rad-na-zaver/
  5. GNU Guile – interpret Scheme vestavitelný do nativních aplikací
    https://www.root.cz/clanky/gnu-guile-interpret-scheme-vestavitelny-do-nativnich-aplikaci/
  6. TinyScheme aneb další interpret jazyka Scheme vestavitelný do dalších aplikací
    https://www.root.cz/clanky/tinyscheme-aneb-dalsi-interpret-jazyka-scheme-vestavitelny-do-dalsich-aplikaci/
  7. Kawa: překvapivě silný a výkonný dialekt Scheme pro JVM
    https://www.root.cz/clanky/kawa-prekvapive-silny-a-vykonny-dialekt-scheme-pro-jvm/
  8. Jazyk Kawa v ekosystému virtuálního stroje Javy
    https://www.root.cz/clanky/jazyk-kawa-v-ekosystemu-virtualniho-stroje-javy/
  9. Zpracování vektorů, matic a N-rozměrných polí v programovacím jazyku Kawa
    https://www.root.cz/clanky/zpracovani-vektoru-matic-a-n-rozmernych-poli-v-programovacim-jazyku-kawa/
  10. Racket: programovací jazyk a současně i platforma pro vývoj nových jazyků
    https://www.root.cz/clanky/racket-programovaci-jazyk-a-soucasne-i-platforma-pro-vyvoj-novych-jazyku/
  11. Makra v Racketu i v dalších lispovských jazycích
    https://www.root.cz/clanky/makra-v-racketu-i-v-dalsich-lispovskych-jazycich/
  12. Základní knihovna jazyka Racket
    https://www.root.cz/clanky/zakladni-knihovna-jazyka-racket/
  13. Jazyk Joker: dialekt Clojure naprogramovaný v Go
    https://www.root.cz/clanky/jazyk-joker-dialekt-clojure-naprogramovany-v-go/
  14. Chicken Scheme – další interpret a především překladač programovacího jazyka Scheme
    https://www.root.cz/clanky/chicken-scheme-dalsi-interpret-a-predevsim-prekladac-programovaciho-jazyka-scheme/
  15. Projekt Gambit – další kvalitní interpret i překladač programovacího jazyka Scheme
    https://www.root.cz/clanky/projekt-gambit-dalsi-kvalitni-interpret-i-prekladac-programovaciho-jazyka-scheme/
  16. Interlisp aneb oživujeme dinosaura
    https://www.root.cz/clanky/interlisp-aneb-ozivujeme-dinosaura/
  17. Propojení světa LISPu se světem JavaScriptu s využitím transpřekladače Wisp
    https://www.root.cz/clanky/propojeni-sveta-lispu-se-svetem-javascriptu-s-vyuzitim-transprekladace-wisp/
  18. Propojení světa LISPu se světem JavaScriptu s využitím transpřekladače Wisp (2.část)
    https://www.root.cz/clanky/propojeni-sveta-lispu-se-svetem-javascriptu-s-vyuzitim-transprekladace-wisp-2-cast/

Články o Elispu:

  1. Úpravy Emacsu a tvorba nových modulů s využitím Emacs Lispu
    https://www.root.cz/clanky/upravy-emacsu-a-tvorba-novych-modulu-s-vyuzitim-emacs-lispu/
  2. Úpravy Emacsu s Emacs Lisp: základní konstrukce jazyka
    https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-zakladni-konstrukce-jazyka/
  3. Úpravy Emacsu s Emacs Lisp: všemocné makro cl-loop a knihovna dash
    https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-vsemocne-makro-cl-loop-a-knihovna-dash/
  4. Úpravy Emacsu s Emacs Lisp: možnosti nabízené knihovnou Dash
    https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-moznosti-nabizene-knihovnou-dash/
  5. Úpravy Emacsu s Emacs Lisp: dokončení popisu Emacs Lispu
    https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-dokonceni-popisu-emacs-lispu/
  6. Úpravy Emacsu s Emacs Lisp: manipulace se základními datovými strukturami Emacsu
    https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-manipulace-se-zakladnimi-datovymi-strukturami-emacsu/

19. Literatura

  1. Peter Seibel
    „Practical Common Lisp“
    2009
  2. Paul Graham
    „ANSI Common Lisp“
    1995
  3. Gerald Gazdar
    „Natural Language Processing in Lisp: An Introduction to Computational Linguistics“
    1989
  4. Peter Norvig
    „Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp“
    1991
  5. Alex Mileler et.al.
    „Clojure Applied: From Practice to Practitioner“
    2015
  6. „Living Clojure: An Introduction and Training Plan for Developers“
    2015
  7. Dmitri Sotnikov
    „Web Development with Clojure: Build Bulletproof Web Apps with Less Code“
    2016
  8. McCarthy
    „Recursive functions of symbolic expressions and their computation by machine, part I“
    1960
  9. R. Kent Dybvig
    „The Scheme Programming Language“
    2009
  10. Max Hailperin
    „Concrete Abstractions“
    1998
  11. Guy L. Steele
    „History of Scheme“
    2006, Sun Microsystems Laboratories
  12. Kolář J., Muller K.:
    „Speciální programovací jazyky“
    Praha 1981
  13. „AutoLISP Release 9, Programmer's reference“
    Autodesk Ltd., October 1987
  14. „AutoLISP Release 10, Programmer's reference“
    Autodesk Ltd., September 1988
  15. 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
  16. Carl Hewitt; Peter Bishop and Richard Steiger
    „A Universal Modular Actor Formalism for Artificial Intelligence“
    1973
  17. Feiman, J.
    „The Gartner Programming Language Survey (October 2001)“
    Gartner Advisory
  18. 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)
  19. Paul Graham
    On Lisp
    Prentice Hall, 1993
    Dostupné online na adrese http://www.paulgraham.com/on­lisptext.html
  20. David S. Touretzky
    Common LISP: A Gentle Introduction to Symbolic Computation (Dover Books on Engineering)
  21. Peter Norvig
    Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp
  22. Patrick Winston, Berthold Horn
    Lisp (3rd Edition)
    ISBN-13: 978–0201083194, ISBN-10: 0201083191
  23. 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

20. Odkazy na Internetu

  1. The Evolution of Lisp
    https://www.csee.umbc.edu/cou­rses/331/resources/papers/E­volution-of-Lisp.pdf
  2. LISP
    https://taoofmac.com/space/dev/lisp
  3. Repositář projektu femtolisp
    https://github.com/JeffBe­zanson/femtolisp
  4. Femtolisp – lightweight, robust lisp interpreter built on reusable C libraries
    https://www.findbestopensou­rce.com/product/femtolisp
  5. YCombinator: Femtolisp: A lightweight, robust, scheme-like Lisp implementation
    https://news.ycombinator.com/i­tem?id=22094722
  6. Learning Julia by Anshul Joshi, Rahul Lakhanpal: Femtolisp
    https://www.oreilly.com/li­brary/view/learning-julia/9781785883279/2e85442f-d100–4b53-b8f7–7d20d62f0255.xhtml
  7. The role of femtolisp in Julia?
    https://discourse.julialang.org/t/the-role-of-femtolisp-in-julia/1902
  8. LispSyntax.jl: A clojure-like lisp syntax for julia
    https://github.com/swadey/Lis­pSyntax.jl
  9. What exactly code lowering is an how to do “unlowering”?
    https://discourse.julialang.org/t/what-exactly-code-lowering-is-an-how-to-do-unlowering/1315
  10. Interlisp.org: Dedicated to Restoring and Preserving the Interlisp experience
    https://github.com/Interlisp
  11. Warren Teitelman
    https://en.wikipedia.org/wi­ki/Warren_Teitelman
  12. InterLISP/65
    http://www.atarimania.com/utility-atari-400–800-xl-xe-interlisp-65_12477.html
  13. Lisp Editing in the 80s – Interlisp SEdit (Video)
    https://www.youtube.com/wat­ch?v=2qsmF8HHskg
  14. Inter-LISP
    http://www.atarimania.com/utility-atari-400–800-xl-xe-inter-lisp_29354.html
  15. InterLISP 65 Editing (video)
    https://www.youtube.com/wat­ch?v=nY_hcazo86A
  16. Datasoft INTER-LISP/65 (Atari Age, chat)
    https://atariage.com/forum­s/topic/116093-datasoft-inter-lisp65/
  17. Marvin Minsky – The beauty of the Lisp language (44/151)
    https://www.youtube.com/wat­ch?v=YaWVHyIBVeI
  18. History of LISP (Interlisp)
    http://www.softwarepreser­vation.org/projects/LISP/in­dex.html#INTERLISP_
  19. Computer-Assisted Instruction (Bits and Bytes, Episode 7)
    https://www.youtube.com/wat­ch?v=eURtTV_qKw8
  20. Můžeme věřit překladačům? Projekty řešící schéma „důvěřivé důvěry“
    https://www.root.cz/clanky/muzeme-verit-prekladacum-projekty-resici-schema-duverive-duvery/
  21. Gambit in the browser
    https://feeley.github.io/gambit-in-the-browser/
  22. A Tour of Scheme in Gambit
    http://dynamo.iro.umontre­al.ca/wiki/images/a/a7/A_Tou­r_of_Scheme_in_Gambit.pdf
  23. Gambit Scheme: Inside Out
    http://www.iro.umontreal.ca/~gam­bit/Gambit-inside-out.pdf
  24. Gambit Internal Documentation
    http://dynamo.iro.umontre­al.ca/wiki/index.php/Inter­nal_Documentation
  25. clojure-scheme: Compiling to Native Code via Scheme
    http://www.iro.umontreal.ca/~gam­bit/Sorenson-Clojure-to-Native-via-Scheme.pdf
  26. Gauche – a Scheme implementation
    http://practical-scheme.net/gauche/
  27. Scheme48
    https://s48.org/
  28. SISC (Second Interpreter of Scheme)
    http://sisc-scheme.org/
  29. The SCM Implementation of Scheme
    https://people.csail.mit.e­du/jaffer/SCM.html
  30. Ypsilon – The ultimate script language system for the video pinball fourth generation
    http://www.littlewingpinba­ll.com/doc/en/ypsilon/index­.html
  31. Chicken Scheme
    https://call-cc.org/
  32. Eggs Unlimited
    http://wiki.call-cc.org/chicken-projects/egg-index-5.html
  33. Chicken Scheme Wiki
    https://wiki.call-cc.org/
  34. CHICKEN for Python programmers
    https://wiki.call-cc.org/chicken-for-python-programmers
  35. Programming for Performance
    http://wiki.call-cc.org/programming-for-performance
  36. Using the compiler
    https://wiki.call-cc.org/man/4/Using%20the%20compiler
  37. CHICKEN Scheme tutorials
    https://wiki.call-cc.org/tutorials
  38. Traditional Turtles
    https://docs.racket-lang.org/turtles/Traditio­nal_Turtles.html
  39. [racket] How best to repeat a function call n times?
    https://lists.racket-lang.org/users/archive/2014-September/064203.html
  40. Racket: Macros
    https://www.it.uu.se/edu/cou­rse/homepage/avfunpro/ht13/lec­tures/Racket-3-Macros.pdf
  41. Beautiful Racket / explainers: Macros
    https://beautifulracket.com/ex­plainer/macros.html
  42. Macros (dokumentace k Racketu)
    https://docs.racket-lang.org/guide/macros.html
  43. Model syntaxe jazyka Racket
    https://docs.racket-lang.org/reference/syntax-model.html
  44. Syntax Objects
    https://docs.racket-lang.org/guide/stx-obj.html
  45. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  46. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  47. Beautiful Racket: an introduction to language-oriented programming using Racket
    https://beautifulracket.com/
  48. Stránky projektu Racket
    https://racket-lang.org/
  49. Dokumentace k projektu Racket
    https://docs.racket-lang.org/index.html
  50. Seznam dostupných balíčků pro Racket
    https://pkgs.racket-lang.org/
  51. Racket na Wikipedii
    https://en.wikipedia.org/wi­ki/Racket_(programming_lan­guage)
  52. Vector Library (R7RS-compatible)
    https://srfi.schemers.org/srfi-133/srfi-133.html
  53. Blogy o Racketu a navazujících technologiích
    https://blog.racket-lang.org/
  54. Prográmky psané v Racketu na RosettaCode
    http://rosettacode.org/wi­ki/Category:Racket
  55. Fear of Macros
    https://www.greghendershott.com/fear-of-macros/
  56. Rackjure
    https://github.com/greghen­dershott/rackjure
  57. 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/
  58. Racket News
    https://racket-news.com/
  59. Racket: Lisp for learning
    https://lwn.net/Articles/795385/
  60. Future of Racket
    https://www.greghendershot­t.com/2019/07/future-of-racket.html
  61. Vectors (pro Gauche)
    https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html
  62. Kawa: Compiling Scheme to Java
    https://www.mit.edu/afs.new/sip­b/project/kawa/doc/kawa-tour.html
  63. Kawa in Languages shootout
    http://per.bothner.com/blog/2010/Kawa-in-shootout/
  64. Kawa 2.0 Supports Scheme R7RS
    https://developers.slashdot­.org/story/14/12/13/2259225/ka­wa-20-supports-scheme-r7rs/
  65. Kawa — fast scripting on the Java platform
    https://lwn.net/Articles/623349/
  66. Tail call (a její optimalizace)
    https://en.wikipedia.org/wi­ki/Tail_call
  67. SLIME (Wikipedia)
    http://en.wikipedia.org/wiki/SLIME
  68. slime.vim
    http://s3.amazonaws.com/mps/slime.vim
  69. What are the best scheme implementations?
    https://www.slant.co/topic­s/5282/~scheme-implementations
  70. Bigloo homepage
    http://www-sop.inria.fr/mimosa/fp/Bigloo/
  71. FTP s tarbally Bigloo
    ftp://ftp-sop.inria.fr/indes/fp/Bigloo
  72. GOTO 2018 • Functional Programming in 40 Minutes • Russ Olsen
    https://www.youtube.com/wat­ch?v=0if71HOyVjY
  73. TinyScheme (stránka na Sourceforge)
    http://tinyscheme.sourcefor­ge.net/home.html
  74. Embedding Tiny Scheme in a Game
    http://www.silicondelight­.com/embedding-tiny-scheme-in-a-game/
  75. Embedding Scheme for a game mission scripting DSL
    http://carloscarrasco.com/embedding-scheme-for-a-game-mission-scripting-dsl.html
  76. Všechny verze TinyScheme na SourceForge
    https://sourceforge.net/pro­jects/tinyscheme/files/ti­nyscheme/
  77. Fork TinyScheme na GitHubu
    https://github.com/yawnt/tinyscheme
  78. Ackermannova funkce
    https://cs.wikipedia.org/wi­ki/Ackermannova_funkce
  79. Ackermann function na Rosetta Code
    https://rosettacode.org/wi­ki/Ackermann_function#Sche­me
  80. Success Stories (lisp.org)
    https://lisp-lang.org/success/
  81. Allegro Common Lisp Success Stories
    https://franz.com/success/
  82. Clojure Success Stories
    https://clojure.org/commu­nity/success_stories
  83. Scheme Quick Reference
    https://www.st.cs.uni-saarland.de/edu/config-ss04/scheme-quickref.pdf
  84. Slajdy o Scheme (od slajdu číslo 15)
    https://docs.google.com/pre­sentation/d/1abmDnKjrq1tcjGvvRNAK­hOiSTSE2lyagtcEPal07Gbo/e­dit
  85. Scheme Cheat Sheet
    https://github.com/smythp/scheme-cheat-sheet
  86. Embedding Lua, embedding Guile
    http://puntoblogspot.blog­spot.com/2013/04/embedding-lua-embedding-guile.html
  87. Lambda Papers
    https://en.wikisource.org/wi­ki/Lambda_Papers
  88. Revised7Report on the Algorithmic Language Scheme
    https://small.r7rs.org/at­tachment/r7rs.pdf
  89. 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/
  90. Why is Scheme my first language in university?
    https://softwareengineerin­g.stackexchange.com/questi­ons/115252/why-is-scheme-my-first-language-in-university
  91. The Perils of JavaSchools
    https://www.joelonsoftware­.com/2005/12/29/the-perils-of-javaschools-2/
  92. How to Design Programs, Second Edition
    https://htdp.org/2019–02–24/index.html
  93. LilyPond
    http://lilypond.org/
  94. LilyPond — Extending (přes Scheme)
    http://lilypond.org/doc/v2­.18/Documentation/extendin­g/scheme-tutorial
  95. Scheme in LilyPond
    http://lilypond.org/doc/v2­.18/Documentation/extendin­g/scheme-in-lilypond
  96. GnuCash
    http://www.gnucash.org/
  97. Custom Reports (in GNU Cash)
    https://wiki.gnucash.org/wi­ki/Custom_Reports
  98. Program by Design
    https://programbydesign.org/
  99. SchemePy
    https://pypi.org/project/SchemePy/
  100. 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
  101. femtolisp
    https://github.com/JeffBe­zanson/femtolisp
  102. (How to Write a (Lisp) Interpreter (in Python))
    http://norvig.com/lispy.html
  103. Repositář s Guile Emacsem
    http://git.hcoop.net/?p=bpt/guile.git
  104. Interacting with Guile Compound Data Types in C
    http://www.lonelycactus.com/gu­ilebook/x1555.html
  105. Calling Guile functions from C
    http://www.lonelycactus.com/gu­ilebook/c1204.html#SECCAL­LGUILEFUNC
  106. Arrays, and other compound data types
    http://www.lonelycactus.com/gu­ilebook/charrays.html
  107. Interacting with Guile Compound Data Types in C
    http://www.lonelycactus.com/gu­ilebook/x1555.html
  108. Guile Reference Manual
    https://www.gnu.org/softwa­re/guile/manual/html_node/in­dex.html
  109. Scheme: Summary of Common Syntax
    https://www.gnu.org/softwa­re/guile/manual/html_node/Syn­tax-Summary.html#Syntax-Summary
  110. Scripting with Guile: Extension language enhances C and Scheme
    https://www.ibm.com/develo­perworks/library/l-guile/index.html
  111. Having fun with Guile: a tutorial
    http://dustycloud.org/misc/guile-tutorial.html
  112. Guile: Loading Readline Support
    https://www.gnu.org/softwa­re/guile/manual/html_node/Lo­ading-Readline-Support.html#Loading-Readline-Support
  113. lispy
    https://pypi.org/project/lispy/
  114. Lython
    https://pypi.org/project/Lython/
  115. Lizpop
    https://pypi.org/project/lizpop/
  116. Budoucnost programovacích jazyků
    http://www.knesl.com/budoucnost-programovacich-jazyku
  117. LISP Prolog and Evolution
    http://blog.samibadawi.com/2013/05/lisp-prolog-and-evolution.html
  118. List of Lisp-family programming languages
    https://en.wikipedia.org/wi­ki/List_of_Lisp-family_programming_languages
  119. clojure_py na indexu PyPi
    https://pypi.python.org/py­pi/clojure_py
  120. PyClojure
    https://github.com/eigenhom­bre/PyClojure
  121. Hy na GitHubu
    https://github.com/hylang/hy
  122. Hy: The survival guide
    https://notes.pault.ag/hy-survival-guide/
  123. Hy běžící na monitoru terminálu společnosti Symbolics
    http://try-hy.appspot.com/
  124. Welcome to Hy’s documentation!
    http://docs.hylang.org/en/stable/
  125. Hy na PyPi
    https://pypi.org/project/hy/#des­cription
  126. Getting Hy on Python
    https://lwn.net/Articles/596626/
  127. Programming Can Be Fun with Hy
    https://opensourceforu.com/2014/02/pro­gramming-can-fun-hy/
  128. Přednáška o projektu Hy (pětiminutový lighttalk)
    http://blog.pault.ag/day/2013/04/02
  129. Hy (Wikipedia)
    https://en.wikipedia.org/wiki/Hy
  130. GNU Emacs Lisp Reference Manual: Point
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Point.html
  131. GNU Emacs Lisp Reference Manual: Narrowing
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Narrowing.html
  132. GNU Emacs Lisp Reference Manual: Functions that Create Markers
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Creating-Markers.html
  133. GNU Emacs Lisp Reference Manual: Motion
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Motion.html#Motion
  134. GNU Emacs Lisp Reference Manual: Basic Char Syntax
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Basic-Char-Syntax.html
  135. Elisp: Sequence: List, Array
    http://ergoemacs.org/emac­s/elisp_list_vs_vector.html
  136. Elisp: Property List
    http://ergoemacs.org/emac­s/elisp_property_list.html
  137. Elisp: Hash Table
    http://ergoemacs.org/emac­s/elisp_hash_table.html
  138. Elisp: Association List
    http://ergoemacs.org/emac­s/elisp_association_list.html
  139. The mapcar Function (An Introduction to Programming in Emacs Lisp)
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­intr/mapcar.html
  140. Anaphoric macro
    https://en.wikipedia.org/wi­ki/Anaphoric_macro
  141. Some Common Lisp Loop Macro Examples
    https://www.youtube.com/wat­ch?v=3yl8o6r_omw
  142. A Guided Tour of Emacs
    https://www.gnu.org/softwa­re/emacs/tour/
  143. The Roots of Lisp
    http://www.paulgraham.com/ro­otsoflisp.html
  144. Evil (Emacs Wiki)
    https://www.emacswiki.org/emacs/Evil
  145. Evil (na GitHubu)
    https://github.com/emacs-evil/evil
  146. Evil (na stránkách repositáře MELPA)
    https://melpa.org/#/evil
  147. Evil Mode: How I Switched From VIM to Emacs
    https://blog.jakuba.net/2014/06/23/e­vil-mode-how-to-switch-from-vim-to-emacs.html
  148. GNU Emacs (home page)
    https://www.gnu.org/software/emacs/
  149. GNU Emacs (texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?GnuEmacs
  150. An Introduction To Using GDB Under Emacs
    http://tedlab.mit.edu/~dr/gdbin­tro.html
  151. An Introduction to Programming in Emacs Lisp
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­intr/index.html
  152. 27.6 Running Debuggers Under Emacs
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­macs/Debuggers.html
  153. GdbMode
    http://www.emacswiki.org/e­macs/GdbMode
  154. Emacs (Wikipedia)
    https://en.wikipedia.org/wiki/Emacs
  155. Emacs timeline
    http://www.jwz.org/doc/emacs-timeline.html
  156. Emacs Text Editors Family
    http://texteditors.org/cgi-bin/wiki.pl?EmacsFamily
  157. Vrapper aneb spojení možností Vimu a Eclipse
    https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse/
  158. 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/
  159. Emacs/Evil-mode – A basic reference to using evil mode in Emacs
    http://www.aakarshnair.com/posts/emacs-evil-mode-cheatsheet
  160. From Vim to Emacs+Evil chaotic migration guide
    https://juanjoalvarez.net/es/de­tail/2014/sep/19/vim-emacsevil-chaotic-migration-guide/
  161. Introduction to evil-mode {video)
    https://www.youtube.com/wat­ch?v=PeVQwYUxYEg
  162. EINE (Emacs Wiki)
    http://www.emacswiki.org/emacs/EINE
  163. EINE (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?EINE
  164. ZWEI (Emacs Wiki)
    http://www.emacswiki.org/emacs/ZWEI
  165. ZWEI (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?ZWEI
  166. Zmacs (Wikipedia)
    https://en.wikipedia.org/wiki/Zmacs
  167. Zmacs (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?Zmacs
  168. TecoEmacs (Emacs Wiki)
    http://www.emacswiki.org/e­macs/TecoEmacs
  169. Micro Emacs
    http://www.emacswiki.org/e­macs/MicroEmacs
  170. Micro Emacs (Wikipedia)
    https://en.wikipedia.org/wi­ki/MicroEMACS
  171. EmacsHistory
    http://www.emacswiki.org/e­macs/EmacsHistory
  172. Seznam editorů s ovládáním podobným Emacsu či kompatibilních s příkazy Emacsu
    http://www.finseth.com/emacs.html
  173. evil-numbers
    https://github.com/cofi/evil-numbers
  174. Debuggery a jejich nadstavby v Linuxu (1.část)
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  175. Debuggery a jejich nadstavby v Linuxu (2.část)
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  176. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  177. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  178. 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/
  179. Org mode
    https://orgmode.org/
  180. The Org Manual
    https://orgmode.org/manual/index.html
  181. Kakoune (modální textový editor)
    http://kakoune.org/
  182. Vim-style keybinding in Emacs/Evil-mode
    https://gist.github.com/tro­yp/6b4c9e1c8670200c04c16036805773d8
  183. Emacs – jak začít
    http://www.abclinuxu.cz/clan­ky/navody/emacs-jak-zacit
  184. Programovací jazyk LISP a LISP machines
    https://www.root.cz/clanky/pro­gramovaci-jazyk-lisp-a-lisp-machines/
  185. Evil-surround
    https://github.com/emacs-evil/evil-surround
  186. Spacemacs
    http://spacemacs.org/
  187. Lisp: Common Lisp, Racket, Clojure, Emacs Lisp
    http://hyperpolyglot.org/lisp
  188. Common Lisp, Scheme, Clojure, And Elisp Compared
    http://irreal.org/blog/?p=725
  189. Does Elisp Suck?
    http://irreal.org/blog/?p=675
  190. Emacs pro mírně pokročilé (9): Elisp
    https://www.root.cz/clanky/emacs-elisp/
  191. If I want to learn lisp, are emacs and elisp a good choice?
    https://www.reddit.com/r/e­macs/comments/2m141y/if_i_wan­t_to_learn_lisp_are_emacs_an­d_elisp_a/
  192. Clojure(Script) Interactive Development Environment that Rocks!
    https://github.com/clojure-emacs/cider
  193. An Introduction to Emacs Lisp
    https://harryrschwartz.com/2014/04/08/an-introduction-to-emacs-lisp.html
  194. Emergency Elisp
    http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html
  195. Lambda calculus
    https://en.wikipedia.org/wi­ki/Lambda_calculus
  196. John McCarthy's original LISP paper from 1959
    https://www.reddit.com/r/pro­gramming/comments/17lpz4/joh­n_mccarthys_original_lisp_pa­per_from_1959/
  197. Micro Manual LISP
    https://www.scribd.com/do­cument/54050141/Micro-Manual-LISP
  198. How Lisp Became God's Own Programming Language
    https://twobithistory.org/2018/10/14/lis­p.html
  199. History of Lisp
    http://jmc.stanford.edu/ar­ticles/lisp/lisp.pdf
  200. The Roots of Lisp
    http://languagelog.ldc.upen­n.edu/myl/llog/jmc.pdf
  201. Racket
    https://racket-lang.org/
  202. The Racket Manifesto
    http://felleisen.org/matthi­as/manifesto/
  203. MIT replaces Scheme with Python
    https://www.johndcook.com/blog/2009/03/26/mit-replaces-scheme-with-python/
  204. Adventures in Advanced Symbolic Programming
    http://groups.csail.mit.e­du/mac/users/gjs/6.945/
  205. Why MIT Switched from Scheme to Python (2009)
    https://news.ycombinator.com/i­tem?id=14167453
  206. Starodávná stránka XLispu
    http://www.xlisp.org/
  207. AutoLISP
    https://en.wikipedia.org/wi­ki/AutoLISP
  208. Seriál PicoLisp: minimalistický a výkonný interpret Lispu
    https://www.root.cz/serialy/picolisp-minimalisticky-a-vykonny-interpret-lispu/
  209. Common Lisp
    https://common-lisp.net/
  210. Getting Going with Common Lisp
    https://cliki.net/Getting%20Started
  211. Online Tutorial (Common Lisp)
    https://cliki.net/online%20tutorial
  212. Guile Emacs
    https://www.emacswiki.org/e­macs/GuileEmacs
  213. Guile Emacs History
    https://www.emacswiki.org/e­macs/GuileEmacsHistory
  214. Guile is a programming language
    https://www.gnu.org/software/guile/
  215. MIT Scheme
    http://groups.csail.mit.e­du/mac/projects/scheme/
  216. SIOD: Scheme in One Defun
    http://people.delphiforum­s.com/gjc//siod.html
  217. CommonLispForEmacs
    https://www.emacswiki.org/e­macs/CommonLispForEmacs
  218. Elisp: print, princ, prin1, format, message
    http://ergoemacs.org/emac­s/elisp_printing.html
  219. Special Forms in Lisp
    http://www.nhplace.com/ken­t/Papers/Special-Forms.html
  220. Basic Building Blocks in LISP
    https://www.tutorialspoin­t.com/lisp/lisp_basic_syn­tax.htm
  221. Introduction to LISP – University of Pittsburgh
    https://people.cs.pitt.edu/~mi­los/courses/cs2740/Lectures/Lis­pTutorial.pdf
  222. Why don't people use LISP
    https://forums.freebsd.org/threads/why-dont-people-use-lisp.24572/
  223. Structured program theorem
    https://en.wikipedia.org/wi­ki/Structured_program_the­orem
  224. Clojure: API Documentation
    https://clojure.org/api/api
  225. Tutorial for the Common Lisp Loop Macro
    http://www.ai.sri.com/pkarp/loop.html
  226. Common Lisp's Loop Macro Examples for Beginners
    http://www.unixuser.org/~e­uske/doc/cl/loop.html
  227. A modern list api for Emacs. No 'cl required.
    https://github.com/magnars/dash.el
  228. The LOOP Facility
    http://www.lispworks.com/do­cumentation/HyperSpec/Body/06_a­.htm
  229. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  230. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  231. Clojure.org: Atoms
    http://clojure.org/Atoms
  232. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  233. Transient Data Structureshttp://clojure.or­g/transients
  234. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  235. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  236. Clojure (na Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  237. Clojure (na Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  238. SICP (The Structure and Interpretation of Computer Programs)
    http://mitpress.mit.edu/sicp/
  239. Pure function
    http://en.wikipedia.org/wi­ki/Pure_function
  240. Funkcionální programování
    http://cs.wikipedia.org/wi­ki/Funkcionální_programová­ní
  241. 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/
  242. Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
    https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/
  243. Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
    https://www.root.cz/clanky/pro­gramovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/
  244. Stránka projektu Jython
    http://www.jython.org/
  245. Jython (Wikipedia)
    https://en.wikipedia.org/wiki/Jython
  246. Scripting for the Java Platform (Wikipedia)
    https://en.wikipedia.org/wi­ki/Scripting_for_the_Java_Plat­form
  247. JSR 223: Scripting for the JavaTM Platform
    https://jcp.org/en/jsr/detail?id=223
  248. List of JVM languages
    https://en.wikipedia.org/wi­ki/List_of_JVM_languages
  249. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  250. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  251. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  252. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  253. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  254. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  255. Economy Size Geek – Interview with Rich Hickey, Creator of Clojure
    https://www.linuxjournal.com/ar­ticle/10708

Autor článku

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