Obsah
1. Common Lisp – žralok mezi programovacími jazyky
2. Stručná historie vývoje Common Lispu
3. Interaktivní vývoj – skutečný REPL a koncept „obrazu“ prostředí
4. Instalace Common Lispu a nastavení prostředí
5. Interní debugger Common Lispu
6. První krůčky s Common Lispem
7. Přerušení výpočtu a jeho obnovení
8. Multiparadigmatický programovací jazyk
10. LISP jako jazyk pro tvorbu (doménově specifických) jazyků
11. DSL pro tvorbu programových smyček – makro loop
12. Použití klauzulí while a until
13. Různé varianty počítané smyčky typu for
14. Procházení prvky seznamu aneb smyčka typu for-each
15. Vybrané další možnosti poskytované makrem loop
16. Překlad LISPovského programu do nativního kódu
17. Repositář s demonstračními příklady
1. Common Lisp – žralok mezi programovacími jazyky
„Most languages are used to solve problem. Lisp is one of the few languages that allows you to write programs that write programs that solve problems“
Svět LISPovských jazyků je dnes velmi rozsáhlý a poměrně nepřehledný, ovšem není se čemu divit, protože první koncept LISPu vznikl již před neuvěřitelnými 61 lety, konkrétně v roce 1958. Jedná se tedy o jeden z prvních vyšších programovacích jazyků vyvinutých pro nasazení na mainframech. Některé z těchto jazyků jsou (s modifikacemi a vylepšeními) používány dodnes, a to nikoli pouze z důvodu konzervativnosti programátorů či nutnosti údržby starého programového kódu stále používaného v produkčním prostředí. V LISPu se totiž objevilo hned několik zajímavých a přelomových konceptů, které samy o sobě dokázaly udržet tento programovací jazyk v hledáčku programátorů. A nejenom to – mnoho myšlenek z LISPu se postupně uplatňuje i v dalších programovacích jazycích, i když je nutné říci, že některé koncepty (homoikonicita a s ní související makra a metaprogramování) jsou do mnoha dalších jazyků přenositelná jen s obtížemi (poměrně úspěšné jsou v tomto ohledu jazyky Rust a Julia se svými systémy maker).
Obrázek 1: O Common Lispu bylo vydáno i relativně velké množství knih.
Dialektů LISPu vzniklo velké množství – určitě několik desítek, pravděpodobně i několik set. Ovšem v současnosti se setkáme především s Common Lispem, Elispem (v Emacsu), jazykem Racket a s Clojure. Dnes se budeme zabývat prvně jmenovaným, tj. Common Lispem. Ten je od roku 1994 definován v ANSI normě a existuje několik jeho implementací, které jsou mezi sebou kompatibilní (zcela jistě na úrovni zdrojových kódů a základních knihoven popsaných v ANSI):
- Steel Bank Common Lisp (SBCL)
- Embeddable Common Lisp (ECL), je překládán do C
- CLISP
- ABCL, zajišťuje interoperabilitu s JVM
- ClozureCL
- CLASP, založena na iteroperabilitě s LLVM
- AllegroCL (proprietary)
- LispWorks (proprietary)
- CMUCL, původně vznikl na Carnegie Mellon University
- GNU Common Lisp
Okolo Common Lispu vznikl poměrně rozsáhlý ekosystém, viz například stránku https://github.com/CodyReichert/awesome-cl.
Obrázek 2: Přebal další knihy o Common Lispu.
2. Stručná historie vývoje Common Lispu
„Common Lisp isn't going anywhere,
and that's a great thing“
Alan Dipert
V této kapitole si alespoň ve stručnosti přiblížíme historii Common Lispu. Ten původně vznikl z Maclispu, což je jeden z dialektů programovacího jazyka LISP, kterému jsme se (i když taktéž jen ve stručnosti) věnovali v článku Interlisp aneb oživujeme dinosaura. Mezi cíle, které si tým, který vznikl za účelem vývoje Maclispu, vytyčil, patřila především snaha o návrh standardizované podoby programovacího jazyka Lisp; navíc se mělo jednat o vylepšení předchozích dialektů LISPu. Tento cíl se ovšem do značné míry podobá cílům dalších projektů, které vznikaly ve zhruba stejnou dobu: ZetaLisp, NIL, Spice Lisp popř. S-1 Lisp. Common Lisp vznikl na základě myšlenek a jazykových konstrukcí, které se v těchto dialektech Lispu objevily – proto také Common Lisp není, minimálně co se týká standardní knihovny tohoto jazyka, zcela konzistentní (což je více než patrné v porovnání se Scheme či Clojure).
Obrázek 3: 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.
Vraťme se však k historii Common Lispu. V roce 1981 se začala tvořit kostra specifikace tohoto jazyka, přičemž za jejím vývojem stál především Bob Engelmore, v té době pracující v ARPA. Bobovým cílem bylo vytvoření standardu, který by však nebyl specifikován nějakou komisí, ale spíše komunitou (ovšem komunitou v dobovém významu toho slova – tedy nejvíce lidmi z univerzitního prostředí). A již o rok později, tedy v roce 1982, byla tehdy první verze specifikace prezentována známým Guy Lewisem Steelem Jr. (mj. spoluautorem jazyka Scheme) na konferenci ACM (ACM symposium on functional programming and LISP). Poté již práce na Common Lispu pokračovala v poměrně rychlém tempu (s ohledem na to, že se jednalo o jazyk, který se stal, slovy tvůrců „součástí přírody“ a již se pravděpodobně nebude a nemusí příliš měnit), takže v roce 1984 mohla vyjít první kniha o tomto jazyku – Common Lisp the Language – která byla současně i jeho poloformální specifikací.
Obrázek 4: Vývoj některých dialektů Lispu.
Zdroj: Wikipedia.
Ovšem z pohledu standardizace je důležitý i rok 1994, kdy vznikl standard ANSI Common Lisp. Po vydání této specifikace se vlastně (minimálně oficiálně) Common Lisp dále neměnil, což ovšem neznamená, že nedocházelo k postupnému rozšiřování, typicky formou knihoven maker a funkcí. Takto například vznikla podpora pro Unicode, I/O operace založené na CLOS či podpora pro souběžný běh výpočtů. V praxi to znamená mj. to, že zdrojové kódy z roku 1994 budou s velkou pravděpodobností použitelné i dnes (pochopitelně pokud nezávisí na nějakých zastaralých knihovnách či operačních systémech). Ostatně je zajímavé (a pro ekosystém jazyka Common Lisp možná i typické), že existuje relativně velké množství knihoven, které nebyly například posledních pět či dokonce deset let změněny („vylepšeny“) a přece jsou bez problému použitelné. Tato stabilita je v některých jiných ekosystémech prakticky nemyslitelná – ostatně vývojáři by se pravděpodobně na pět let nemodifikovanou knihovnu pro (například) Python či JavaScript dívali skrz prsty.
3. Interaktivní vývoj – skutečný REPL a koncept „obrazu“ prostředí
„ Part of what makes Lisp distinctive is that it is designed to evolve. As new abstractions become popular (object-oriented programming, for example), it always turns out to be easy to implement them in Lisp. Like DNA, such a language does not go out of style.“
Paul Graham
Základem vývoje v (Common) LISPu je interaktivní prostředí založené na REPLu, tedy na okamžitém vyhodnocování zapsaných výrazů s výpisem jejich výsledků. Ovšem v případě Common Lispu je REPL navíc doplněn o debugger popsaný níže. V krátkosti – při vzniku chyby se neprovádí „rozbalovací“ fáze založená na zpětném procházení zásobníkových rámců. Tato operace je ponechána na uživateli, který tak může skutečně zkoumat „živý“ program.
Navíc Common Lisp dokáže pracovat s perzistentními objekty uloženými v tzv. obrazu (image), což je podobný koncept, jaký nalezneme například ve Smalltalku. Touto zajímavou technologií se budeme zabývat příště (dnes je tato technologie díky perzistentním databázím méně důležitá, než v osmdesátých letech, kdy byl tento koncept rozvinut).
Obrázek 5: Základem smyčky REPL je funkce EVAL. Zde je uveden prakticky celý její zdrojový kód získaný z dvoustránkové publikace o LISPu napsané McCarthym. Na první straně je popsán celý jazyk (jeho syntaxe i sémantika), stranu druhou zabírá právě výpis funkce EVAL.
4. Instalace Common Lispu a nastavení prostředí
Jak již víme z předchozích kapitol, je nutné Common Lisp chápat jako přesnou specifikaci jazyka a knihoven, nikoli jako konkrétní implementaci. Pro Linux lze využít více implementací Common Lispu, přičemž pravděpodobně nejpoužívanější je CMU Common Lisp zkracovaný na CMUCL a taktéž Steel Bank Common Lisp neboli zkráceně SBCL. Existuje však například i GNU Common Lisp atd. V této kapitole si ukážeme instalaci SBCL, protože právě balíček s touto variantou Common Lispu naleznete v repositářích mnoha distribucí Linuxu.
Instalace na systémy založené na balíčcích RPM (Fedora, RHEL):
# dnf install sbcl Last metadata expiration check: 0:25:24 ago on Fri 28 Jan 2022 07:36:45 AM EST. Dependencies resolved. ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: sbcl x86_64 2.0.1-5.fc34 beaker-Fedora-Everything 15 M Installing dependencies: cl-asdf noarch 20101028-19.fc34 beaker-Fedora-Everything 87 k common-lisp-controller noarch 7.4-21.fc34 beaker-Fedora-Everything 24 k Transaction Summary ================================================================================ Install 3 Packages Total download size: 16 M Installed size: 73 M Is this ok [y/N]: Downloading Packages: (1/3): common-lisp-controller-7.4-21.fc34.noarc 1.6 MB/s | 24 kB 00:00 (2/3): cl-asdf-20101028-19.fc34.noarch.rpm 838 kB/s | 87 kB 00:00 (3/3): sbcl-2.0.1-5.fc34.x86_64.rpm 24 MB/s | 15 MB 00:00 -------------------------------------------------------------------------------- Total 24 MB/s | 16 MB 00:00 Running transaction check Transaction check succeeded. Running transaction test Transaction test succeeded. Running transaction Preparing : 1/1 Installing : cl-asdf-20101028-19.fc34.noarch 1/3 Installing : common-lisp-controller-7.4-21.fc34.noarch 2/3 Installing : sbcl-2.0.1-5.fc34.x86_64 3/3 Running scriptlet: sbcl-2.0.1-5.fc34.x86_64 3/3 Verifying : cl-asdf-20101028-19.fc34.noarch 1/3 Verifying : common-lisp-controller-7.4-21.fc34.noarch 2/3 Verifying : sbcl-2.0.1-5.fc34.x86_64 3/3 Installed: cl-asdf-20101028-19.fc34.noarch common-lisp-controller-7.4-21.fc34.noarch sbcl-2.0.1-5.fc34.x86_64 Complete!
Instalace na systémy založené na balíčcích Debianu:
# sudo apt-get install sbcl Reading package lists... Done Building dependency tree Reading state information... Done Suggested packages: sbcl-doc sbcl-source slime The following NEW packages will be installed: sbcl 0 upgraded, 1 newly installed, 0 to remove and 2 not upgraded. Need to get 0 B/8 439 kB of archives. After this operation, 43,3 MB of additional disk space will be used. Selecting previously unselected package sbcl. (Reading database ... 291609 files and directories currently installed.) Preparing to unpack .../sbcl_2%3a2.0.1-3_amd64.deb ... Unpacking sbcl (2:2.0.1-3) ... Setting up sbcl (2:2.0.1-3) ... Processing triggers for man-db (2.9.1-1) ...
Prostředí SBCL se spustí následovně:
$ sbcl This is SBCL 2.0.1.debian, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. *
SBCL není (alespoň většinou) slinkován s knihovnami typu readline. Proč je to však tak důležité, že se o tom explicitně zmiňujeme? 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, ani 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 v případě potřeby předat soubor se symboly pro automatické doplňování. Nástroj rlwrap se instaluje snadno:
$ dnf install rlwrap Last metadata expiration check: 0:33:16 ago on Sat 09 Apr 2022 06:45:42 AM EDT. Dependencies resolved. ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: rlwrap x86_64 0.45.2-1.fc34 updates 132 k Installing dependencies: perl-File-Slurp noarch 9999.32-3.fc34 beaker-Fedora 31 k perl-lib x86_64 0.65-477.fc34 updates 25 k Transaction Summary ================================================================================ Install 3 Packages Total download size: 188 k Installed size: 399 k Is this ok [y/N]: y Downloading Packages: (1/3): perl-File-Slurp-9999.32-3.fc34.noarch.rp 3.6 MB/s | 31 kB 00:00 (2/3): perl-lib-0.65-477.fc34.x86_64.rpm 197 kB/s | 25 kB 00:00 (3/3): rlwrap-0.45.2-1.fc34.x86_64.rpm 649 kB/s | 132 kB 00:00 -------------------------------------------------------------------------------- Total 142 kB/s | 188 kB 00:01
S využitím rlwrap se bude prostředí SBCL spouštět následujícím způsobem:
$ rlwrap sbcl
Se (zdánlivě) stejným výsledkem, ovšem v mnoha ohledech s vylepšenou příkazovou řádkou:
This is SBCL 2.0.1-5.fc34, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. *
5. Interní debugger Common Lispu
Důležitou součástí SBCL je i interní debugger, který umožňuje jak detekci problémů, tak i interaktivní ladění a opravu kódu. Debugger je spuštěn buď při vzniku chyby či výjimky, nebo například zavoláním funkce cerror. Podívejme se na první možnost. Do prostředí SBCL zapíšeme neznámý identifikátor (resp. symbol):
* foobar
Namísto pouhého konstatování, že došlo k chybě, se spustí debugger, který uživateli nabídne několik možností:
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "main thread" RUNNING {1000510083}>: The variable FOOBAR is unbound. Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [CONTINUE ] Retry using FOOBAR. 1: [USE-VALUE ] Use specified value. 2: [STORE-VALUE] Set specified value and use it. 3: [ABORT ] Exit debugger, returning to top level. (SB-INT:SIMPLE-EVAL-IN-LEXENV FOOBAR #<NULL-LEXENV>) 0]
Odlišně se debugger zachová v případě, že se pokusíme zavolat neznámou funkci:
* (foobar)
; in: FOOBAR ; (FOOBAR) ; ; caught STYLE-WARNING: ; undefined function: COMMON-LISP-USER::FOOBAR ; ; compilation unit finished ; Undefined function: ; FOOBAR ; caught 1 STYLE-WARNING condition debugger invoked on a UNDEFINED-FUNCTION in thread #<THREAD "main thread" RUNNING {1000510083}>: The function COMMON-LISP-USER::FOOBAR is undefined. Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [CONTINUE ] Retry calling FOOBAR. 1: [USE-VALUE ] Call specified function. 2: [RETURN-VALUE ] Return specified values. 3: [RETURN-NOTHING] Return zero values. 4: [ABORT ] Exit debugger, returning to top level. ("undefined function")
Zajímavá je možnost RETURN-VALUE, která umožňuje pokračovat ve (složitém) výpočtu nahrazením volání funkce za uživatelem zadanou hodnotu. Například můžete spustit program, který má komunikovat se specifickou a nedostupnou službou atd.
Příklad vyvolání debuggeru programově, tj. zavoláním funkce cerror:
(defun factorial (n) (if (minusp n) (cerror "continue with negative value?" "negative value ~s" n)) (* n (factorial (- n 1))))
Spustíme SBCL a načteme do něj zdrojový kód této funkce:
$ sbcl --load broken_factorial.lisp This is SBCL 2.0.1.debian, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information.
Po dosažení záporného n dojde k chybě a vyvolání debuggeru:
* (factorial 10) debugger invoked on a SIMPLE-ERROR in thread #<THREAD "main thread" RUNNING {1000510083}>: negative value -1 Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [CONTINUE] continue with negative value? 1: [ABORT ] Exit debugger, returning to top level. (FACTORIAL -1) source: (CERROR "continue with negative value?" "negative value ~s" N)
6. První krůčky s Common Lispem
V této kapitole se ve stručnosti seznámíme se základními vlastnostmi LISPu, ovšem s ohledem na to, že již známe způsob programování ve Scheme a Clojure (viz odkazy uvedené v osmácté kapitole), takže je možné se zaměřit na největší rozdíly. Ještě předtím se musíme alespoň ve stručnosti seznámit s různými variantami funkce print, protože tyto varianty budeme používat v demonstračních příkladech. V následující tabulce je vypsána většina funkcí, které lze použít pro zobrazení nějakých hodnot uživateli. Dnes využijeme funkce nazvané princ, terpri a v některých příkladech i funkci format (což je obdoba printf):
Funkce | Stručný popis |
---|---|
tisk hodnoty takovým způsobem, aby ji bylo možné načíst zpět pomocí read | |
prin1 | dtto, ovšem bez konce řádku |
princ | tisk hodnoty tak, aby byla dobře čitelná uživatelem (nekompatibilní s read) |
terpri | odřádkování (terminate print) |
format | naformátování zprávy podle zadané šablony a její tisk či vrácení ve formě řetězce |
V programovacím jazyce LISP je možné kromě základních (interních, primitivních) funkcí definovat a následně i volat funkce uživatelské, podobně jako v mnoha dalších programovacích jazycích. Ve skutečnosti je velká část programů napsaných v LISPu tvořena právě definicemi nových funkcí vystavěných na základě standardních funkcí a několika speciálních forem. V Common Lispu, což je jedna z nejrozšířenějších a také nejkomplexnějších implementací tohoto jazyka, se funkce vytváří pomocí speciální formy nazvané defun (define function). Formát volání formy defun při tvorbě nové funkce je velmi jednoduchý, programátor si ovšem musí dát pozor na správné uzávorkování:
(defun název_funkce(parametry funkce) tělo funkce)
Návratovou hodnotou nově vytvořené funkce (po jejím zavolání a vykonání) je hodnota výrazu tvořícího tělo funkce, což znamená, že není nutné používat nějakou formu příkazu return tak, jak je tomu v mnoha dalších programovacích jazycích. Ukažme si nyní způsob vytvoření dvou jednoduchých funkcí a následného zavolání těchto funkcí:
; funkce vracející druhou mocninu svého jediného parametru (defun sqr(x) (* x x)) ; funkce, která sečte hodnoty svých dvou parametrů a vrátí výsledek součtu (defun plus(x y) (+ x y)) ; zavoláme první funkci (sqr 42) 1764 ; a nyní funkci druhou (plus 2 3) 5 ; funkce lze samozřejmě libovolným způsobem kombinovat (plus (sqr 3) (sqr 4)) 25 ; podporovány jsou i zlomky (plus 1/2 2/3) 7/6
Common Lisp patří mezi ty dialekty Lispu, které pokládají rovnítko mezi hodnotou nil a prázdným seznamem (což jsou zcela ekvivalentní hodnoty):
nil NIL '() NIL () NIL
Globální proměnné je vhodné před jejich použitím deklarovat:
(defvar x 1)
Teprve poté lze měnit jejich hodnotu, například přes setf (zde se Common Lisp liší například od Elispu):
(setf x 2)
Pokus o nastavení nedefinované proměnné vede k zobrazení varování:
* (setf y 10) ; in: SETF Y ; (SETF Y 10) ; ==> ; (SETQ Y 10) ; ; caught WARNING: ; undefined variable: COMMON-LISP-USER::Y ; ; compilation unit finished ; Undefined variable: ; Y ; caught 1 WARNING condition 10
Definice konstanty:
(defconstant A 42)
Typová kontrola v době překladu (tomuto zajímavému tématu bude věnován samostatný článek):
* (defun foo () (concatenate 'string "+" A)) ; in: DEFUN FOO ; (CONCATENATE 'STRING "+" A) ; ; caught WARNING: ; Constant 42 conflicts with its asserted type SEQUENCE. ; See also: ; The SBCL Manual, Node "Handling of Types" ; ; compilation unit finished ; caught 1 WARNING condition FOO
7. Přerušení výpočtu a jeho obnovení
Debugger, který je součástí většiny implementací Common Lispu, dokáže zareagovat i na běhovou chybu. Ovšem nikoli tak, že by pouze vypsal obsah zásobníkových rámců (což je například chování Pythonu i JVM – kde se tak možnost ladění do jisté míry ztratí). Naopak – k „rozvinovací“ (unwinding) fázi nedojde, resp. přesněji řečeno se Common Lisp zeptá programátora, jakou operaci má konkrétně provést. Například je možné kód opravit a spustit znovu, a to přesně z toho místa, kde byl běh přerušen (tedy s využitím původního obsahu zásobníkových rámců).
Podívejme se na konkrétní, velmi jednoduchý příklad. Jedná se o klasický rekurzivní výpočet faktoriálu, ovšem používá se zde neznámý symbol default, který není nikde nastaven:
(defun factorial (n) (cond ((zerop n) default) (T (* n (factorial (- n 1))))))
Pokusme se nyní tento zdrojový kód načíst do SBCL:
$ sbcl --load broken_factorial2.lisp
V průběhu načítání se již dopředu vypíše varování a nedefinované proměnné. Ovšem kód se načte, neboť Lisp předpokládá, že se proměnná může (na globální úrovni) kdykoli později objevit, a to ještě před zavoláním funkce factorial (bylo by ostatně zajímavé tento koncept přidat i do dalších podobně koncipovaných jazyků):
This is SBCL 2.0.1.debian, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information. ; file: /home/ptisnovs/src/lisp-families/common-lisp/broken_factorial2.lisp ; in: DEFUN FACTORIAL ; (COND ((ZEROP N) DEFAULT) (T (* N (FACTORIAL (- N 1))))) ; ==> ; (IF (ZEROP N) ; DEFAULT ; (THE T (* N (FACTORIAL (- N 1))))) ; ; caught WARNING: ; undefined variable: COMMON-LISP-USER::DEFAULT ; ; compilation unit finished ; Undefined variable: ; DEFAULT ; caught 1 WARNING condition
Nyní se pokusme funkci factorial zavolat:
* (factorial 10)
Podle očekávání dojde k chybě, ovšem debugger nám umožňuje pokračovat ve výpočtu zadáním specifikované hodnoty, která se za default dosadí:
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "main thread" RUNNING {1000560083}>: The variable DEFAULT is unbound. Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL. restarts (invokable by number or by possibly-abbreviated name): 0: [CONTINUE ] Retry using DEFAULT. 1: [USE-VALUE ] Use specified value. 2: [STORE-VALUE] Set specified value and use it. 3: [ABORT ] Exit debugger, returning to top level. (FACTORIAL 0) source: (COND ((ZEROP N) DEFAULT) (T (* N (FACTORIAL (- N 1)))))
Zkusme tedy vybrat možnost číslo 1 a dosadit hodnotu default:
0] 1 Enter a form to be evaluated: 1 3628800
8. Multiparadigmatický programovací jazyk
O Lispu (resp. někdy dokonce přímo o Common Lispu) se v některých dokumentech tvrdí, že se jedná o funkcionální jazyk. Ve skutečnosti je Common Lisp spíše multiparadigmatickým jazykem, který mj. umožňuje vytvářet programy s využitím metodiky funkcionálního programování (funkce, funkce vyššího řádu, uzávěry, neměnitelné hodnoty, striktně lokální proměnné). Ovšem stejně dobře je možné použít klasický imperativní styl (měnitelné seznamy, globální proměnné, …), objektově orientovaný styl (typicky s využitím CLOS – což je téma na samostatný článek) a především se Common Lisp používá i jako metajazyk. Navíc je možné do LISPu přidávat další doménově specifické jazyky nebo i například do něho „vložit“ další programovací jazyk (příkladem tohoto typu je projekt April, což je vlastně APL dostupné přímo z LISPu).
Ostatně podívejme se na následující zcela legální kód napsaný pro Common Lisp, který se podobá starému (dobrému?) BASICu s čísly řádků a skoky vytvořenými s využitím go (v BASICu pomocí GOTO):
(tagbody 10 (print "Hello!") 20 (sleep 2) 30 (go 10))
9. Makrosystém Common Lispu
Jednou z nejzajímavějších vlastností LISPu (přesněji řečeno některých jeho implementací, jejichž typickým zástupcem je i Common Lisp) je možnost tvorby maker. Vzhledem k tomu, že LISPovské programy jsou tvořeny, stejně jako data, pomocí rekurzivně vnořených seznamů, jsou LISPovská makra založena na manipulaci se seznamy tvořícími program, což je velký rozdíl například oproti makrům implementovaným v céčkovém preprocesoru, kde se jedná o poměrně jednoduché (a z pohledu programátora značně primitivní) textové záměny. Vzhledem k tomu, že LISPovská makra dokážou manipulovat s vlastním programem, je možné pomocí nich vytvářet například úplně nové jazykové konstrukce (různé smyčky, podmíněné příkazy, částečně vyhodnocované formy atd.) s vlastní syntaxí, což je poměrně unikátní vlastnost, kterou u většiny dalších programovacích jazyků nenajdeme. Způsob definice maker se v některých ohledech podobá definici funkcí, ale mezi funkcemi a makry existuje jeden zásadní rozdíl.
LISPovské funkce získávají jako svoje argumenty LISPovské hodnoty, tj. většinou atomy, (anonymní) funkce nebo seznamy, a vrací taktéž nějakou LISPovskou hodnotu – opět se může jednat o atom, (anonymní) funkci nebo seznam. Funkce jsou vyhodnocovány (volány) až při spuštění programu. Makra jako svůj vstup získávají LISPovský kód (zapsaný formou rekurzivně zanořeného seznamu) a vrací taktéž LISPovský kód, což nepředstavuje oproti funkcím žádný zásadnější rozdíl. Ovšem na rozdíl od funkcí jsou makra volána již při prvotním zpracovávání programu, podobně jako jsou céčková makra zpracovávána céčkovým preprocesorem (cpp) ještě před vlastní kompilací. Teprve výsledek volání makra (nazývaný taktéž expanze makra) je považován za zápis výrazu, který může být dále zpracován, tj. buď vyhodnocen (interpretační varianty LISPu) nebo zkompilován (varianty LISPu vybavené překladačem). Poznamenejme ještě, že v těle makra se může vyskytovat volání dalšího makra, což znamená, že LISP musí při expanzi maker použít rekurzi.
10. LISP jako jazyk pro tvorbu (doménově specifických) jazyků
Doménově specifické jazyky (anglicky DSL neboli Domain-Specific Language) jsou velmi důležitou součástí informatiky a mnohé z nich jsou velmi úspěšné a rozšířené do mnoha oblastí. Za připomenutí stojí například jazyk pro popis regulárních výrazů, jenž je podporován jak mnoha nástroji, tak i knihovnami, popř. je přímo součástí některých obecných programovacích jazyků (Perl apod.). I v některých dalších případech je tento přístup velmi užitečný a rozšířený, ostatně například SQL je s velkou pravděpodobností nejpopulárnějším samostatně chápaným doménově specifickým jazykem neboli DSL vůbec, protože umožňuje snadné optimalizace dotazů a vůbec pokládání dotazů čitelným, pochopitelným a přenositelným způsobem. Dalším doménově specifickým jazykem, s nímž jsme se již na stránkách Roota v rámci několika článků seznámili, je jazyk Gherkin určený pro popis chování systémů a pro psaní BDD testů. Dalším příkladem je PostScript.
Mnohé z doménově specifických jazyků nejsou Turingovsky kompletní (úplný), což však není nedostatek, ale mnohdy naopak požadovaná vlastnost. Příkladem mohou být DSL, v nichž není možné zapsat programové smyčky ani rekurzi – tudíž je většinou výpočet resp. vyhodnocení výrazu časově dosti přesně určené. Další DSL neumožňují explicitní alokaci paměti, což může být v dané oblasti použití taktéž výhodné. Nasazení DSL oproti plnohodnotnému jazyku tedy může být výhodné, protože cíleně omezené možnosti takového jazyka můžeme chápat jako formu „sémantického sandboxingu“ (právě proto jsou regulární výrazy regulární).
Právě LISP a tím pádem i Common Lisp, je velmi vhodným jazykem pro tvorbu doménově specifických jazyků, a to z toho důvodu, že lze relativně snadno manipulovat s abstraktním syntaktickým stromem (s využitím maker) ještě před vlastním zpracováním kódu ve funkci eval. A příkladů DSL vytvořených v LISPu existuje poměrně velké množství. V navazujících kapitolách se seznámíme s makrem loop, které do Common Lispu přidává DSL pro tvorbu různých programových smyček, a to mnohdy i značně složitých:
(loop repeat 1000 for x = (random 100) if (evenp x) collect x into evens else collect x into odds finally (return (values evens odds)))
Dále knihovna spinneret umožňuje zápis struktury HTML stránky přímo v LISPu, pochopitelně s možností použití maker atd.:
(let ((*html-style* :human)) (with-html (:div (:p "Text " (:a "link text") " more text"))))
Z dalších známějších DSL můžeme jmenovat i SxQL pro zápis dotazů do databáze:
(select (:title :author :year) (from :books) (where (:and (:>= :year 1995) (:< :year 2010))) (order-by (:desc :year)))
11. DSL pro tvorbu programových smyček – makro loop
Smyčka loop ve formě, v jaké byla navržena v Common Lispu (a poté částečně převzata do Elispu), programátorům nabízí svůj vlastní doménově specifický jazyk (DSL). Z dalších demonstračních příkladů bude patrné, že tento jazyk používá styl zápisu, který je kombinací klasických strukturovaných jazyků (Algol, Pascal, C) a možností LISPu. Je tomu tak z toho důvodu, aby bylo přímo ze zápisu smyčky, typicky již po přečtení prvního řádku, patrné, jak bude smyčka prováděna. K tomuto účelu se uvnitř smyčky loop používají symboly for, repeat, in, finally atd., které mají svůj speciální význam, ale pouze uvnitř samotné formy loop. Tím se loop do značné míry liší od smyček v klasických jazycích, které programátory „nutí“ realizovat kód smyčky v jejím těle, což nemusí být vždy idiomatické.
Podívejme se nyní na pravděpodobně nejjednodušší prakticky použitelný příklad využívající smyčku loop, v níž bude použita dvojice symbolů se speciálním významem, o nichž jsme se zmínili v předchozím odstavci. Konkrétně budeme implementovat programovou smyčku, jejíž tělo se bude n-krát opakovat. K zápisu této varianty smyčky nám pomohou dva symboly se jmény repeat a do. Povšimněte si, že zápis smyčky vypadá prakticky stejně, jako by tomu bylo v některém z klasických strukturovaných jazyků (samozřejmě pokud si odmyslíme kulaté závorky, do kterých toto makro vkládáme a které jsou v Lispu v této formě povinné):
(loop repeat 10 do (princ "Hello world!") (terpri))
Makro loop zavolané tímto způsobem nevrací žádnou hodnotu, takže se předpokládá, že smyčka vykoná svoji činnost jen díky tomu, že některá funkce volaná při každé iteraci bude mít vedlejší efekt, například že vypíše zprávu na obrazovku atd., což je ostatně přesně náš případ. Po spuštění výše popsané smyčky se na výstupu skutečně zobrazí deset totožných zpráv:
Hello world! Hello world! Hello world! Hello world! Hello world! Hello world! Hello world! Hello world! Hello world! Hello world!
12. Použití klauzulí while a until
Ve smyčce loop je možné v případě potřeby použít i klauzule while a until, za nimiž se zapisuje podmínka. Ta je od těla smyčky oddělena speciálním symbolem do, takže zápisy vypadají následovně:
Vyhodnocení podmínky na začátku každé iterace, tělo smyčky se zavolá, pokud je podmínka splněna:
(loop while podmínka do ...)
Vyhodnocení podmínky na začátku každé iterace, tělo smyčky se zavolá, pokud podmínka splněna naopak není (po splnění podmínky se smyčka opustí):
(loop until podmínka do ...)
Demonstrační příklad bude velmi jednoduchý, protože v něm použijeme jedinou řídicí proměnnou i, kterou budeme nejprve zmenšovat o jedničku a poté v druhé smyčce naopak zvyšovat až do chvíle, kdy překročí hodnotu 10:
(defvar i 10) (loop while (> i 0) do (format T "i = ~d~%" i) (setq i (- i 1))) (princ "rebound") (terpri) (loop until (> i 10) do (format T "i = ~d~%" i) (setq i (+ i 1)))
Výsledek bude vypadat takto:
i = 10 i = 9 i = 8 i = 7 i = 6 i = 5 i = 4 i = 3 i = 2 i = 1 rebound i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10
13. Různé varianty počítané smyčky typu for
Makro loop samozřejmě podporuje i tvorbu klasických programových smyček, v nichž se postupně mění hodnota počitadla. Základní forma této smyčky vypadá následovně:
(loop for i to 10 do (format T "i = ~d~%" i))
Výsledek ukazuje, že se počítá od nuly a končí se až po dosažení koncové hodnoty (pozor – ne o jedničku dříve):
i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10
Alternativně můžeme v tomto případě namísto symbolu to použít spíše upto:
(loop for i upto 10 do (format T "i = ~d~%" i))
A to se shodným výsledkem:
i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10
Mnohdy potřebujeme, aby horní meze nebylo dosaženo a smyčka skončila těsně předtím (což do určité míry odpovídá Pythonovskému for i in range(x,y)). Namísto komplikovaných výpočtů použijte below a nikoli to či upto:
(loop for i below 10 do (format T "i = ~d~%" i))
V tomto případě se skutečně počítá jen do 9 a nikoli 10:
i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9
Užitečná je možnost přidání další (libovolné) podmínky, která pro počitadlo musí platit. Jsou přeskočeny ty iterace, kdy podmínka není splněna (ovšem smyčka není ukončena):
(loop for i below 10 when (evenp i) do (format T "i = ~d~%" i))
Výsledkem je v tomto případě sekvence sudých čísel:
i = 0 i = 2 i = 4 i = 6 i = 8
Popř. naopak:
(loop for i below 10 when (oddp i) do (format T "i = ~d~%" i))
Výsledkem je nyní sekvence čísel lichých:
i = 1 i = 3 i = 5 i = 7 i = 9
Samozřejmě je možné v případě potřeby specifikovat i počáteční hodnotu počitadla; tj. nemusí se vždy začínat na nule:
(loop for i from 1 to 10 do (format T "i = ~d~%" i))
Výsledek:
i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10
Totožná smyčka, ovšem s jiným symbolem (lépe čitelným):
(loop for i from 1 upto 10 do (format T "i = ~d~%" i))
Výsledek je stejný:
i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9 i = 10
Kombinace from a below:
(loop for i from 1 below 10 do (format T "i = ~d~%" i))
Výsledek je kratší o poslední iteraci:
i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 i = 7 i = 8 i = 9
Další kombinace již obsahují klauzuli when:
(loop for i from 1 to 10 when (evenp i) do (format T "i = ~d~%" i))
Výsledek:
i = 2 i = 4 i = 6 i = 8 i = 10
(loop for i from 1 upto 10 when (evenp i) do (format T "i = ~d~%" i))
Výsledek:
i = 2 i = 4 i = 6 i = 8 i = 10
(loop for i upfrom 1 upto 10 when (evenp i) do (princ (format "i = %d\n" i)))
Výsledek:
i = 2 i = 4 i = 6 i = 8 i = 10
(loop for i from 1 below 10 when (evenp i) do (princ (format "i = %d\n" i)))
Výsledek:
i = 2 i = 4 i = 6 i = 8
Další demonstrační příklad si již ukážeme v celku. Používá se v něm symbol by, za nímž se udává krok, tj. o jakou hodnotu se bude počitadlo měnit. Výchozí hodnotou je pochopitelně jednička:
(loop for i from 0 to 30 by 3 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i from 0 upto 30 by 3 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i upfrom 0 upto 30 by 3 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i upfrom 0 below 30 by 3 do (princ (format "i = %d\n" i))) (princ "===========================\n") (loop for i from 0 to 30 by 3 when (evenp i) do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i from 0 upto 30 by 3 when (evenp i) do (princ (format "i = %d\n" i))) (princ "---------------------------\n")
Prozatím jsme v předchozích smyčkách počitadlo vždy zvyšovali, ať již o jedničku nebo o jinou hodnotu. Počítat je však možné i opačným směrem. V tomto případě však nestačí za by zadat záporné číslo! Je nutné použít jiný zápis, a to s využitím symbolů downto nebo above. Opět si ukažme některé povolené kombinace (pozor na rozdílné chování downto a above):
(loop for i from 10 downto 1 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i from 10 above 1 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i upfrom 10 above 1 do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i from 10 downto 1 when (evenp i) do (princ (format "i = %d\n" i))) (princ "---------------------------\n") (loop for i from 10 above 1 when (evenp i) do (princ (format "i = %d\n" i)))
14. Procházení prvky seznamu aneb smyčka typu for-each
V případě, že se má procházet všemi prvky seznamu (nebo vektoru), lze použít klauzuli for in, která používá následující styl zápisu:
(loop for prvek in seznam ... ... ... tělo smyčky ... ... ...)
Vidíme, že se tento zápis opět do značné míry podobá syntaxi, s níž se setkáme v běžných programovacích jazycích. Typicky se tato smyčka používá ve chvíli, kdy se v ní volá funkce s vedlejším efektem. Pokud tomu tak není a je nutné ze smyčky vrátit výsledek aplikace nějaké funkce na prvky seznamu, používá se klauzule collect, a to přibližně tímto způsobem:
(loop for prvek in seznam collect prvek)
V následujícím příkladu je tato varianta smyčky použita, i když se ve skutečnosti dá nahradit funkcí mapcar:
(defvar lst '(1 2 3 4 5 6 7 8 9 10)) (print (loop for i in lst collect i)) (print (loop for i in lst collect (* i i))) (defun factorial (n) (cond ((zerop n) 1) (T (* n (factorial (- n 1)))))) (print (loop for i in lst collect (factorial i)))
Výsledky:
(0 1 2 3 4 5 6 7 8 9 10) (0 1 4 9 16 25 36 49 64 81 100) (1 1 2 6 24 120 720 5040 40320 362880 3628800)
Existuje ještě jedna varianta smyčky for-each, ovšem tato varianta používá zápis se symbolem on a nikoli in:
(loop for prvek on seznam collect prvek)
Tato varianta prochází seznamem odlišně – v první iteraci se do řídicí proměnné smyčky vloží celý seznam, ve druhé iteraci seznam bez prvního prvku atd. atd.:
(defvar lst '(1 2 3 4 5 6 7 8 9 10)) (defvar result (loop for i on lst collect i)) (dolist (item result) (print item))
Výsledek nyní bude značně odlišný – bude se totiž jednat o seznam seznamů:
(0 1 2 3 4 5 6 7 8 9 10) (1 2 3 4 5 6 7 8 9 10) (2 3 4 5 6 7 8 9 10) (3 4 5 6 7 8 9 10) (4 5 6 7 8 9 10) (5 6 7 8 9 10) (6 7 8 9 10) (7 8 9 10) (8 9 10) (9 10) (10)
15. Vybrané další možnosti poskytované makrem loop
V předchozích demonstračních příkladech jsme pro získání výsledné hodnoty smyčky používali klauzuli collect. Použít je však možné i klauzuli append, která pracuje podobně, ale pokud této klauzuli předáme seznam, budou všechny jeho prvky přidány do výsledného seznamu (každý zvlášť). Můžeme tím tedy nahradit operaci flatten:
(defvar lst '(1 2 3 4 5 6 7 8 9 10)) (defvar result (loop for i in lst collect i)) (dolist (item result) (print item)) (terpri) (princ "-------------------------------------") (defvar kids '((alfa beta) () (gama delta) (omega) ())) (setq result (loop for i in kids append i)) (dolist (item result) (print item))
S výsledkem:
1 2 3 4 5 6 7 8 9 10 ------------------------------------- ALFA BETA GAMA DELTA OMEGA
Podívejme se ještě na některé složitější konstrukce, které dokážeme s makrem loop vytvořit. Poměrně často se setkáme se situací, kdy je nutné vypočítat sumu všech prvků nějakého seznamu nebo vektoru. To lze provést několika způsoby (reduce atd.), ovšem při použití smyčky loop lze k tomuto účelu využít klauzuli sum pro akumulaci výsledků:
(defvar lst '(1 2 3 4 5 6 7 8 9 10)) (defvar result (loop for i in lst sum i)) (format T "Result: ~d~%" result)
Předchozí zápis vracel implicitně jedinou hodnotu ze smyčky, a to konkrétně sumu prvků. Toto chování lze popsat i explicitně s využitím klauzule finally, do níž zapíšeme příkaz, který se má vykonat při ukončování smyčky. Povšimněte si, že zde používáme lokální proměnnou total (lze ji pojmenovat různě):
(terpri) (setq result (loop for i in lst sum i into total finally (return total))) (format T "Result: ~d~%" result)
Výsledkem bude v obou případech stejná zpráva:
Result: 55
Předchozí demonstrační příklad je možné ještě více „vyšperkovat“, například vypočítat počet všech prvků, jejich součet, maximální hodnotu a minimální hodnotu. To vše v jediné smyčce a bez použití podmínek. Povšimněte si způsobu, jak ze smyčky vrátit více hodnot:
(defvar lst '(1 2 3 4 5 6 7 8 9 10)) (setq result (loop for i in lst count i into counter sum i into total maximize i into max-value minimize i into min-value finally return (list min-value max-value total counter))) (format T "Min value ~d~%" (nth 0 result)) (format T "Max value ~d~%" (nth 1 result)) (format T "Sum value ~d~%" (nth 2 result)) (format T "Values ~d~%" (nth 3 result))
Výsledky vypočtené předchozím příkladem:
Min value 0 Max value 10 Sum value 55 Values 11
16. Překlad LISPovského programu do nativního kódu
Velmi důležitým konceptem, který v Common Lisp nalezneme, je překlad celého prostředí Common Lispu, pochopitelně včetně uživatelem vytvořeného projektu, do nativního kódu. Výsledkem překladu je skutečně celé lispovské prostředí, a to včetně debuggeru atd. To má několik důsledků, například možnost relativně snadno ladit službu běžící v (před)produkčním prostředí atd., výkonnost například webového serveru naprogramovaného v Lispu je obecně mnohonásobně vyšší, než v případě Ruby či Pythonu atd.
Podívejme se nyní na způsob vytvoření spustitelného (a v rámci dané architektury a operačního systému i přenositelného) programu, po jehož spuštění se vypočítá faktoriál. Nejprve spustíme prostředí SBCL:
$ sbcl This is SBCL 2.0.1.debian, an implementation of ANSI Common Lisp. More information about SBCL is available at <http://www.sbcl.org/>. SBCL is free software, provided as is, with absolutely no warranty. It is mostly in the public domain; some portions are provided under BSD-style licenses. See the CREDITS and COPYING files in the distribution for more information.
Dále načteme zdrojový kód uložený v souboru factorial2.lisp:
* (load "factorial2.lisp") T
A provedeme překlad zavoláním funkce sb-ext:save-lisp-and-die, které se předá jméno výsledného spustitelného kódu, příznak, že se má skutečně vygenerovat spustitelný kód a v neposlední řadě se uvede i jméno funkce, která se má spustit (na rozdíl od Clojure tedy nemusíme tuto funkci pojmenovat main-):
* (sb-ext:save-lisp-and-die "factorial" :executable t :toplevel 'print-factorials)
Průběh překladu (je prakticky okamžitý):
[undoing binding stack and other enclosing state... done] [performing final GC... done] [defragmenting immobile space... (fin,inst,fdefn,code,sym)=348+687+14943+16321+24770... done] [saving current Lisp image into factorial: writing 0 bytes from the read-only space at 0x50000000 writing 384 bytes from the static space at 0x50100000 writing 22183936 bytes from the dynamic space at 0x1000000000 writing 1798144 bytes from the immobile space at 0x50300000 writing 10579968 bytes from the immobile space at 0x52100000 done]
Výsledkem překladu je dosti objemný soubor o velikosti 34MB!:
$ ls -lah factorial -rwxr-xr-x. 1 tisnik tisnik 34M Apr 10 15:01 factorial
Který je ovšem plně funkční:
$ ./factorial 1 2 6 24 120 720 5040 40320 362880 3628800 39916800 479001600 6227020800 87178291200 1307674368000 20922789888000 355687428096000 6402373705728000 121645100408832000 2432902008176640000
Závislosti na dalších systémových knihovnách jsou v tomto případě skutečně malé:
$ ldd factorial linux-vdso.so.1 (0x00007fff3d663000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f78929bc000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7892999000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f789297d000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f789282e000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f789263c000) /lib64/ld-linux-x86-64.so.2 (0x00007f78929d9000)
Na tomto místě je vhodné poznamenat, že například do určité míry „konkurenční“ Clojure je založeno na premise „virtuální stroje jsou budoucí operační systémy“ (což se dnes ukazuje být spíše nepravdivé), takže se namísto přenositelného binárního souboru vytváří Java archivy. Z tohoto pohledu je přístup Common Lispu až překvapivě moderní.
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í v prostředí Common Lispu 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:
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):
- 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/ - PicoLisp: minimalistický a přitom překvapivě výkonný interpret Lispu
https://www.root.cz/clanky/picolisp-minimalisticky-a-pritom-prekvapive-vykonny-interpret-lispu/ - 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/ - 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/ - GNU Guile – interpret Scheme vestavitelný do nativních aplikací
https://www.root.cz/clanky/gnu-guile-interpret-scheme-vestavitelny-do-nativnich-aplikaci/ - 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/ - 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/ - Jazyk Kawa v ekosystému virtuálního stroje Javy
https://www.root.cz/clanky/jazyk-kawa-v-ekosystemu-virtualniho-stroje-javy/ - 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/ - 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/ - Makra v Racketu i v dalších lispovských jazycích
https://www.root.cz/clanky/makra-v-racketu-i-v-dalsich-lispovskych-jazycich/ - Základní knihovna jazyka Racket
https://www.root.cz/clanky/zakladni-knihovna-jazyka-racket/ - Jazyk Joker: dialekt Clojure naprogramovaný v Go
https://www.root.cz/clanky/jazyk-joker-dialekt-clojure-naprogramovany-v-go/ - 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/ - 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/ - Interlisp aneb oživujeme dinosaura
https://www.root.cz/clanky/interlisp-aneb-ozivujeme-dinosaura/ - 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/ - 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:
- Ú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/ - Úpravy Emacsu s Emacs Lisp: základní konstrukce jazyka
https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-zakladni-konstrukce-jazyka/ - Ú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/ - Ú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/ - Úpravy Emacsu s Emacs Lisp: dokončení popisu Emacs Lispu
https://www.root.cz/clanky/upravy-emacsu-s-emacs-lisp-dokonceni-popisu-emacs-lispu/ - Ú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
O Common Lispu, Scheme či Clojure, tedy o třech (s velkou pravděpodobností) nejpoužívanějších dialektech LISPu, vyšlo poměrně velké množství literatury. Pro Common Lisp je typická jeho velká stabilita, a to minimálně od roku 1994, což mj. znamená, že i původní vydaní prvních dvou dále zmíněných knih je zcela bez problémů použitelné i dnes (a obě knihy jsou navíc dobře čitelné):
- 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 adrese 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
20. Odkazy na Internetu
- Common Lisp
https://lisp-lang.org/ - Why You Should Learn Lisp In 2022?
https://www.youtube.com/watch?v=GWdf1flcLoM - LOOP Common Lisps Superior For
https://www.youtube.com/watch?v=i4tmF_1nZng - Lisp VS C benchmarks
https://programming-language-benchmarks.vercel.app/lisp-vs-c - Common Lisp: An elegant design pattern
https://www.youtube.com/watch?v=9597LFlvMuE - Common Lisp Macros By Example Tutorial
https://lisp-journey.gitlab.io/blog/common-lisp-macros-by-example-tutorial/ - The Common Lisp Cookbook
https://lispcookbook.github.io/cl-cookbook/ - The Evolution of Lisp
https://www.csee.umbc.edu/courses/331/resources/papers/Evolution-of-Lisp.pdf - Awesome CL
https://github.com/CodyReichert/awesome-cl - LISP
https://taoofmac.com/space/dev/lisp - Repositář projektu femtolisp
https://github.com/JeffBezanson/femtolisp - Femtolisp – lightweight, robust lisp interpreter built on reusable C libraries
https://www.findbestopensource.com/product/femtolisp - YCombinator: Femtolisp: A lightweight, robust, scheme-like Lisp implementation
https://news.ycombinator.com/item?id=22094722 - Learning Julia by Anshul Joshi, Rahul Lakhanpal: Femtolisp
https://www.oreilly.com/library/view/learning-julia/9781785883279/2e85442f-d100–4b53-b8f7–7d20d62f0255.xhtml - The role of femtolisp in Julia?
https://discourse.julialang.org/t/the-role-of-femtolisp-in-julia/1902 - LispSyntax.jl: A clojure-like lisp syntax for julia
https://github.com/swadey/LispSyntax.jl - 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 - Interlisp.org: Dedicated to Restoring and Preserving the Interlisp experience
https://github.com/Interlisp - Warren Teitelman
https://en.wikipedia.org/wiki/Warren_Teitelman - InterLISP/65
http://www.atarimania.com/utility-atari-400–800-xl-xe-interlisp-65_12477.html - Lisp Editing in the 80s – Interlisp SEdit (Video)
https://www.youtube.com/watch?v=2qsmF8HHskg - Inter-LISP
http://www.atarimania.com/utility-atari-400–800-xl-xe-inter-lisp_29354.html - InterLISP 65 Editing (video)
https://www.youtube.com/watch?v=nY_hcazo86A - Datasoft INTER-LISP/65 (Atari Age, chat)
https://atariage.com/forums/topic/116093-datasoft-inter-lisp65/ - Marvin Minsky – The beauty of the Lisp language (44/151)
https://www.youtube.com/watch?v=YaWVHyIBVeI - History of LISP (Interlisp)
http://www.softwarepreservation.org/projects/LISP/index.html#INTERLISP_ - Computer-Assisted Instruction (Bits and Bytes, Episode 7)
https://www.youtube.com/watch?v=eURtTV_qKw8 - 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/ - Gambit in the browser
https://feeley.github.io/gambit-in-the-browser/ - A Tour of Scheme in Gambit
http://dynamo.iro.umontreal.ca/wiki/images/a/a7/A_Tour_of_Scheme_in_Gambit.pdf - Gambit Scheme: Inside Out
http://www.iro.umontreal.ca/~gambit/Gambit-inside-out.pdf - Gambit Internal Documentation
http://dynamo.iro.umontreal.ca/wiki/index.php/Internal_Documentation - clojure-scheme: Compiling to Native Code via Scheme
http://www.iro.umontreal.ca/~gambit/Sorenson-Clojure-to-Native-via-Scheme.pdf - Gauche – a Scheme implementation
http://practical-scheme.net/gauche/ - Scheme48
https://s48.org/ - SISC (Second Interpreter of Scheme)
http://sisc-scheme.org/ - The SCM Implementation of Scheme
https://people.csail.mit.edu/jaffer/SCM.html - Ypsilon – The ultimate script language system for the video pinball fourth generation
http://www.littlewingpinball.com/doc/en/ypsilon/index.html - Chicken Scheme
https://call-cc.org/ - Eggs Unlimited
http://wiki.call-cc.org/chicken-projects/egg-index-5.html - Chicken Scheme Wiki
https://wiki.call-cc.org/ - CHICKEN for Python programmers
https://wiki.call-cc.org/chicken-for-python-programmers - Programming for Performance
http://wiki.call-cc.org/programming-for-performance - Using the compiler
https://wiki.call-cc.org/man/4/Using%20the%20compiler - CHICKEN Scheme tutorials
https://wiki.call-cc.org/tutorials - Traditional Turtles
https://docs.racket-lang.org/turtles/Traditional_Turtles.html - [racket] How best to repeat a function call n times?
https://lists.racket-lang.org/users/archive/2014-September/064203.html - 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) - Vector Library (R7RS-compatible)
https://srfi.schemers.org/srfi-133/srfi-133.html - 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 - Vectors (pro Gauche)
https://practical-scheme.net/gauche/man/gauche-refe/Vectors.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 - LISP: Lex Fridman's favorite programming language
https://www.youtube.com/watch?v=cMMiaCtOzV0 - What is the Curse of Lisp?
https://www.youtube.com/watch?v=_J3×5yvQ8yc - Array Programming Re-Imagined in Lisp
https://github.com/phantomics/april - What is Nil Punning?
https://www.youtube.com/watch?v=xiYKuDk6G-o - Python VS Common Lisp, workflow and ecosystem
https://lisp-journey.gitlab.io/pythonvslisp/ - A fast-moving Common Lisp software distribution
https://ultralisp.org/ - Numcl
https://github.com/numcl/numcl - Petalisp
https://github.com/marcoheisig/Petalisp - Common Lisp for the Curious Clojurian – Alan Dipert – Scicloj meeting 19
https://www.youtube.com/watch?v=44Q9ew9JH_U - Peter Norvig on Python
https://serverhorror.wordpress.com/2010/10/19/peter-norvig-on-python/ - A History of the Common Lisp
https://www.cleverism.com/skills-and-tools/common-lisp/ - Starting with Common Lisp in 2020
http://dnaeon.github.io/starting-with-common-lisp-in-2020/ - JACL: JavaScript Assisted Common Lisp
https://tailrecursion.com/JACL/