Obsah
1. Basilisp: interpret programovacího jazyka Clojure integrovaný s Pythonem
2. Python VM ve funkci platformy pro další programovací jazyky
4. Instalace projektu Basilisp
5. První kroky v interaktivní smyčce jazyka Basilisp
6. Literály a jednoduché formy, s nimiž se v Basilispu pracuje
8. Složené formy: strukturované datové typy
9. Příklady konstrukce kolekcí v programovacím jazyku Basilisp
10. Operace s kolekcemi a nekonečnými sekvencemi
11. Predikáty, zjištění typových informací za běhu
12. Řídicí struktury (speciální formy a makra)
13. Ukázky využití vybraných řídicích struktur
15. Balíčky dodávané se samotným jazykem Basilisp
16. Interoperabilita s Pythonem
17. Využití balíčků Pythonu přímo z Basilispu
18. Předchozí části seriálu o LISPovských programovacích jazycích
1. Basilisp: interpret programovacího jazyka Clojure integrovaný s Pythonem
Svět programovacího jazyka LISP je velmi rozsáhlý a dá se říci, že i pestrý. Jak již bylo napsáno v perexu dnešního článku, vznikl koncept tohoto programovacího jazyka již před neuvěřitelnými 65 roky a od té doby bylo vytvořeno několik set, ale s poměrně velkou pravděpodobností i několik tisíc implementací LISPu popř. od něj odvozených jazyků Scheme a Clojure. LISPy tak najdeme jak na osmibitových domácích mikropočítačích na jedné straně, tak i na superpočítačích na straně druhé. V dnešním článku se seznámíme s projektem nazvaným Basilisp. Jedná se o interpret programovacího jazyka Clojure, který je integrovaný s platformou Pythonu (naproti tomu klasický Clojure je integrovaný s JVM a ClojureScript s JavaScriptem). Velkou předností Basilispu je téměř dokonalé navázání na Python a jeho knihovny – dokonce je integrace lepší, než Clojure+Java, protože Basilisp má s Pythonem podobný typový systém.
Spojení dialektu LISPu s virtuálním strojem Pythonu popř. přímo s programovacím jazykem Python (tzv. interop) není zajímavé jen z technologického hlediska, protože může mít i praktické využití. Ostatně LISP byl jazykem používaným pro vývoj systémů umělé inteligence, a to už v padesátých letech minulého století (z dnešního pohledu se ale mnohdy jednalo spíš o hledání slepých uliček). A dnes má v oblasti AI a strojového učení stejně výsadní postavení Python, takže se vlastně spojení LISP+Python jeví jako poměrně pragmatická volba.
2. Python VM ve funkci platformy pro další programovací jazyky
Fakt, že různé dialekty jazyků LISP a Scheme (popř. Clojure, který lze považovat za moderní reinkarnaci LISPu) vznikají pro prakticky všechny moderní virtuální stroje (typicky pro JVM, VM JavaScriptu, WASM nebo VM Pythonu) vlastně není nic překvapivého. Musíme si totiž uvědomit, že praktická použitelnost programovacího jazyka je do značné míry určena i celým ekosystémem, který je programátorům, kteří chtějí tento jazyk začít používat, k dispozici. A ekosystém Pythonu je dnes již velmi rozsáhlý a obsahuje kvalitní a v celém světě používané knihovny i celé frameworky, takže se může jednat o vhodný základ, na němž je možné postavit moderní varianty LISPu.
Na podobné myšlence ostatně vznikl i výše zmíněný jazyk Clojure, který vlastně vůbec nemá svůj vlastní virtuální stroj. Clojure vzniklo pro virtuální stroj Javy (JVM – Java Virtual Machine), další varianty Clojure byly implementovány pro CLR (ClojureCLR) a ClojureScript, který je kompilovaný do JavaScriptu, takže může běžet buď v prohlížeči, v Node.js atd. V každém případě však Clojure dokáže využít všechny dostupné knihovny pro zvolenou platformu.
Pro virtuální stroj jazyka Python (Python VM) je v současnosti k dispozici hned několik dialektů LISPu, Scheme či Clojure. Jedná se například o méně známé projekty Lizpop, Lispy či Lython, dále o SchemePy, Clojure-py a taktéž velmi zajímavým způsobem implementovaný programovací jazyk nazvaný Hy. Do této kategorie částečně spadá i programovací jazyk Pixie, se kterým jsme se již na stránkách Roota seznámili. A dalším členem této již tak rozsáhlé rodiny je projekt Basilisp, kterému se budeme primárně věnovat v dnešním článku.
3. Projekt Basilisp
Projekt Basilisp je implementací programovacího jazyka Clojure (resp. přesněji řečeno velké části tohoto jazyka) pro platformu klasického CPythonu. Ovšem to, že Basilisp běží nad virtuálním strojem Pythonu není pouhý implementační detail, ale důležitá vlastnost, protože Basilisp dokáže prakticky bezproblémově volat funkce a metody samotného Pythonu, dokáže importovat Pythonní balíčky atd. Rozhraní mezi Pythonem a Basilispem samozřejmě není zcela bezproblémové, protože se zde střetává svět Pythonu s (obecně) měnitelnými datovými strukturami na straně jedné a svět neměnitelných a persistentních datových struktur na straně druhé. Ovšem, ostatně jak uvidíme v navazujících kapitolách, je možné i tento problém řešit celkem elegantním způsobem. Basilisp samotný obsahuje podporu pro interaktivní smyčku REPL, která se navíc inicializuje rychleji, než je tomu v klasickém Clojure postaveném nad virtuálním strojem Javy.
4. Instalace projektu Basilisp
Basilisp je dostupný ve formě běžného Pythonního balíčku, takže je možné pro jeho instalaci použít například nástroj pip. Ovšem pro první pokusy s tímto projektem bude lepší instalace do samostatného adresáře, resp. přesněji řečeno do virtuálního prostředí Pythonu. Pro tuto variantu instalaci použiji nástroj uv, i když naprosto stejným způsobem lze využít pdm atd.
Nejprve si necháme vygenerovat adresář se základní kostrou Pythonního projektu:
$ uv init basilisp-project Initialized project `basilisp-project` at `/tmp/ramdisk/basilisp-project`
Měl by vzniknout nový adresář s následujícím obsahem:
drwxr-xr-x. 3 ptisnovs ptisnovs 160 Nov 8 10:32 . drwxr-xr-x. 3 ptisnovs ptisnovs 60 Nov 8 10:32 .. drwxr-xr-x. 6 ptisnovs ptisnovs 180 Nov 8 10:32 .git -rw-r--r--. 1 ptisnovs ptisnovs 109 Nov 8 10:32 .gitignore -rw-r--r--. 1 ptisnovs ptisnovs 94 Nov 8 10:32 main.py -rw-r--r--. 1 ptisnovs ptisnovs 162 Nov 8 10:32 pyproject.toml -rw-r--r--. 1 ptisnovs ptisnovs 5 Nov 8 10:32 .python-version -rw-r--r--. 1 ptisnovs ptisnovs 0 Nov 8 10:32 README.md
Přesuneme se do nově vytvořeného adresáře a nainstalujeme Basilisp do virtuálního prostředí:
$ cd basilisp-project $ uv add basilisp Using CPython 3.12.10 interpreter at: /usr/bin/python3.12 Creating virtual environment at: .venv Resolved 8 packages in 481ms Prepared 3 packages in 236ms Installed 7 packages in 12ms + attrs==25.4.0 + basilisp==0.4.0 + immutables==0.21 + prompt-toolkit==3.0.52 + pyrsistent==0.20.0 + typing-extensions==4.15.0 + wcwidth==0.2.14
Současně by měly být zaregistrovány nové příkazy/nástroje spustitelné přes uv run:
$ uv run Provide a command or script to invoke with `uv run <;command>` or `uv run <script>.py`. The following commands are available in the environment: - basilisp - basilisp-run - python - python3 - python3.12
My budeme v praktické části článku spouštět příkaz/nástroj basilisp, který má sám další volby:
$ uv run basilisp
usage: basilisp [-h] {bootstrap,nrepl-server,repl,run,test,version} ...
Basilisp is a Lisp dialect inspired by Clojure targeting Python 3.
positional arguments:
{bootstrap,nrepl-server,repl,run,test,version}
sub-commands
bootstrap bootstrap the Python installation to allow importing Basilisp namespaces
nrepl-server start the nREPL server
repl start the Basilisp REPL
run run a Basilisp script or code or namespace
test run tests in a Basilisp project
version print the version of Basilisp
options:
-h, --help show this help message and exit
5. První kroky v interaktivní smyčce jazyka Basilisp
Basilisp je vybaven plnohodnotnou interaktivní smyčkou REPL (Read Eval Print Loop), která nabízí možnost editace příkazového řádku, práci s historií příkazů, obsahuje jednoduchou nápovědu (postačuje napsat část příkazu a nabídne se jeho doplnění), zvýraznění syntaxe a především pak „doskoky“ na párové závorky, což je pro LISPovský programovací jazyk velmi důležité.
REPL se spustí následovně:
$ uv run basilisp repl basilisp.user=>
Zadané výrazy jsou ihned vyhodnocovány. Například forma * (makro nebo funkce) pro součin hodnot se ihned po potvrzení klávesou Enter vyhodnotí a výsledek se vypíše:
basilisp.user=> (* 6 7) 42
Ke každému načtenému symbolu je možné zobrazit nápovědu pomocí doc:
basilisp.user=> (doc +) ------------------------ basilisp.core/+ ([] [x] [x y] [x y & args]) Sum the arguments together. If no arguments given, returns 0. nil
Nápověda k samotné funkci zobrazující nápovědu:
basilisp.user=> (doc doc) ------------------------ basilisp.repl/doc ([&env &form v]) Print the docstring from an interned Var if found. ``v`` must be a symbol which resolves to a Var. nil
Nápověda k velmi užitečné konstrukci range:
basilisp.user=> (doc range) ------------------------ basilisp.core/range ([] [end] [start end] [start end step]) Return a range of integers from ``start``\. If ``end`` is specified, the sequence will terminate at ``end``\. If ``step`` is specified, that amount will be added for each iteration. ``step`` may be negative. nil
Zajímavé a užitečné je, že vývojář má přímý přístup k základním funkcím Pythonu. Ty se volají naprosto stejně, jakoby se jednalo o samotné funkce Basilispu:
basilisp.user=> (hex 42) "0x2a"
basilisp.user=> (abs -42) 42
Ovšem zavolat můžeme například i vestavěnou funkci help (ta je interaktivní):
basilisp.user=> (help) Welcome to Python 3.12's help utility! If this is your first time using Python, you should definitely check out the tutorial at https://docs.python.org/3.12/tutorial/. Enter the name of any module, keyword, or topic to get help on writing Python programs and using Python modules. To get a list of available modules, keywords, symbols, or topics, enter "modules", "keywords", "symbols", or "topics". Each module also comes with a one-line summary of what it does; to list the modules whose name or summary contain a given string such as "spam", enter "modules spam". To quit this help utility and return to the interpreter, enter "q" or "quit". help>
Příklad spuštění a vyhodnocení range (podrobnosti budou uvedeny později):
basilisp.user=> (range 10) (0 1 2 3 4 5 6 7 8 9)
Nápověda k další velmi užitečné funkci (vyššího řádu) nazvané reduce:
basilisp.user=> (doc reduce) ------------------------ basilisp.core/reduce ([f coll] [f val coll]) Reduce ``coll`` by ``f``\. If ``val`` is not supplied and ``coll`` has no elements, ``f`` will be called with no arguments and the result will be returned. If ``val`` is not supplied and ``coll`` has one element, the result of ``(f (first val))`` is returned. If ``val`` is not supplied and ``coll`` has elements, repeatedly reduce ``coll`` by calling ``f`` on successive elements in ``coll``\. If ``val`` is supplied and ``coll`` has no elements, return ``val` and ``f`` will not be called. If ``val`` is supplied and ``coll`` has elements, repeatedly reduce ``coll`` by calling ``f`` on successive elements in ``coll``\, starting with ``val``\. If ``f`` returns a ``reduced`` value at any point, reduction will terminate and the reduced value will be returned immediately.
Využití funkce reduce pro výpočet faktoriálu 1000 (podrobnosti opět budou uvedeny později):
basilisp.user=> (reduce * (range 1 1000)) 40238726007709377354370243392300398571937486421071463254379991042993851239862902 05920442084869694048004799886101971960586316668729948085589013238296699445909974 24504087073759918823627727188732519779505950995276120874975462497043601418278094 64649629105639388743788648733711918104582578364784997701247663288983595573543251 31853239584630755574091142624174743493475534286465766116677973966688202912073791 43853719588249808126867838374559731746136085379534524221586593201928090878297308 43139284440328123155861103697680135730421616874760967587134831202547858932076716 91324484262361314125087802080002616831510273418279777047846358681701643650241536 91398281264810213092761244896359928705114964975419909342221566832572080821333186 11681155361583654698404670897560290095053761647584772842188967964624494516076535 34081989013854424879849599533191017233555566021394503997362807501378376153071277 61926849034352625200015888535147331611702103968175921510907788019393178114194545 25722386554146106289218796022383897147608850627686296714667469756291123408243920 81601537808898939645182632436716167621791689097799119037540312746222899880051954 44414282012187361745992642956581746628302955570299024324153181617210465832036786 90611726015878352075151628422554026517048330422614397428693306169089796848259012 54583271682264580665267699586526822728070757813918581788896522081643483448259932 66043367660176999612831860788386150279465955131156552036093988180612138558600301 43569452722420634463179746059468257310379008402443243846565724501440282188525247 09351906209290231364932734975655139587205596542287497740114133469627154228458623 77387538230483865688976461927383814900140767310446640259899490222221765904339901 88601856652648506179970235619389701786004081188972991831102117122984590164192106 88843871218556461249607987229085192968193723886426148396573822911231250241866493 53143970137428531926649875337218940694281434118520158014123344828015051399694290 15348307764456909907315243327828826986460278986432113908350621709500259738986355 42771967428222487575867657523442202075736305694988250879689281627538488633969099 59826280956121450994871701244516461260379029309120889086942028510640182154399457 15680594187274899809425474217358240106367740459574178516082923013535808184009699 63725242305608559037006242712434169090041536901059339838357779394109700277534720 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000000000000000000000 00000
6. Literály a jednoduché formy, s nimiž se v Basilispu pracuje
Nyní se již (konečně!) můžeme seznámit se základními stavebními prvky, na kterých je programovací jazyk Basilisp postaven. Všechny příklady, které zde budou ukázány, jsou spouštěny interaktivně ze smyčky REPL, což znamená, že každý výraz je nejprve načten (read), vyhodnocen (evaluate), posléze je jeho výsledek vypsán na standardní výstup (print) a následně je očekáváno interaktivní zadání dalšího výrazu (loop). Všechny dále uvedené výrazy jsou jednořádkové, takže na prvním řádku je vypsán vlastní výraz (tak jak má být opsán do konzole) a na řádku druhém výsledek tohoto výrazu.
V předchozích větách jsme sice pro jednoduchost používali slovo „výraz“ odpovídající spíše jazykům typu Céčka či Javy, ovšem v případě Basilispu je, podobně jako v jiných variantách LISPu či Scheme, základním uceleným prvkem programu takzvaná forma (form). Právě formy se postupně zpracovávají v interaktivní smyčce REPL a REPL taktéž kontroluje, zda uživatel skutečně zadal validní formu. V programovacím jazyku Basilisp (ale i v Clojure) existují čtyři základní typy forem:
- literály
- symboly a hesla (keywords)
- složené formy (v podstatě se jedná o seznamy představující volání funkce)
- speciální formy (podobají se složeným formám, ale interně se vyhodnocují odlišným způsobem, například se rekurzivně nevyhodnocují vnitřní podvýrazy atd.)
Nejjednodušším typem formy jsou literály, protože ty se v interaktivní smyčce REPL vyhodnocují samy na sebe. Na literály se můžeme dívat jako na konstanty nějakého primitivního datového typu, mezi které v programovacím jazyce Basilisp patří především čísla (k dispozici jsou různé formy reprezentace), znaky, řetězce a pravdivostní hodnoty. Nyní si ukážeme několik příkladů, které naznačí, jak s literály pracuje REPL a tudíž i samotný programovací jazyk Basilisp.
Řetězec je prostě … řetězec. Zapisuje se do dvojitých uvozovek (apostrofy a zpětné apostrofy mají odlišný význam):
basilisp.user=> "Hello" Hello
Důležité je, že řetězce jsou – podobně jako v Pythonu nebo i v Javě – konstantní a tudíž i neměnné (immutable), což sice v některých případech může vést k tvorbě neefektivních operací, kterým se však lze v Basilispu většinou zcela vyhnout. To, že jsou řetězce neměnné však zjednodušuje tvorbu bezpečných vícevláknových aplikací, řetězce lze využívat jako klíče do asociativních polí atd. atd., takže přednosti většinou převažují nad zápory.
Pozor je nutné dát na to, že některé další typy Pythonovských řetězců nejsou podporovány. Například nelze uvést prefix u:
basilisp.user=> u"Hello"
exception: <class 'basilisp.lang.compiler.exception.CompilerException'>
phase: :analyzing
message: unable to resolve symbol 'u' in this context
form: u
location: <REPL Input>:1
Podporovány nejsou ani formátovací řetězce (a už vůbec ne řetězce konvertované na šablonu, což je novinka Pythonu 3.14):
basilisp.user=> f"Hello"
exception: <class 'basilisp.lang.compiler.exception.CompilerException'>
phase: :analyzing
message: unable to resolve symbol 'f' in this context
form: f
location: <REPL Input>:1
basilisp.user=> """Hello""" ""
Použití literálů představujících pravdivostní hodnoty asi nikoho nepřekvapí:
basilisp.user=> true true basilisp.user=> false false
basilisp.user=> True
exception: <class 'basilisp.lang.compiler.exception.CompilerException'>
phase: :analyzing
message: unable to resolve symbol 'True' in this context
form: True
location: <REPL Input>:1
Číselné literály jsou již z pohledu programátora mnohem zajímavější, protože numerické hodnoty lze reprezentovat různým způsobem, využívat různé číselné soustavy, pracovat s racionálními čísly atd.
Základem je zápis literálu představujícího celé číslo (odpovídající konvencím zápisu podle Céčka, C++ či Javy):
basilisp.user=> 42 42
Před numerickou hodnotu lze zapsat i základ číselné soustavy (konkrétně před r může být uvedeno číslo 2 až 36):
basilisp.user=> 2r101010 42 basilisp.user=> 16r2a 42 basilisp.user=> 36r16 42
Různé zápisy numerických hodnot s plovoucí řádovou čárkou, interně se hodnoty ukládají podle normy IEEE 754 (vlastně stejně, jako je tomu i v Pythonu):
basilisp.user=> 3.14 3.14 basilisp.user=> 1e10 10000000000 basilisp.user=> 1e-10 1e-10
Mnohé LISPovské programovací jazyky podporují práci se zlomky, resp. přesněji řečeno s racionálními čísly. Stejně tak je tomu i v jazyce Basilisp:
basilisp.user=> 100/3 100/3
Výpočet, jehož výsledkem je numerická hodnota (zjednodušený zlomek):
basilisp.user=> (+ 7/6 3/4) 23/12
Od Clojure jsou odvozeny i numerické typy představující neomezené hodnoty a typ s neomezenou přesností i rozsahem:
basilisp.user=> 1234M 1234 basilisp.user=> 1234N 1234
A konečně se setkáme s hodnotou nil, která v LISPovských jazycích nahrazuje None/NULL:
basilisp.user=> nil nil
Pozor ovšem na to, že hodnota None z Pythonu není podporována – namísto ní se vždy použije nil:
basilisp.user=> None
exception: <class 'basilisp.lang.compiler.exception.CompilerException'>
phase: :analyzing
message: unable to resolve symbol 'None' in this context
form: None
location: <REPL Input>:1
| Slovo | Původ | Význam |
|---|---|---|
| null | latina | ne+ullus, žádný |
| nil | latina | nihil, nic (též zkratka „Not In List“) |
| none | stará angličtina | ne+an, ani jeden |
7. Symboly a hesla
Nejjednodušší typ formy – literály – jsme si již popsali v předchozí kapitole, takže se pojďme věnovat dalším třem typům forem. Druhým typem formy podporovaným programovacím jazykem Basilisp jsou takzvané symboly známé už z klasického LISPu (i Clojure), ke kterým se v Basilisp ještě přidávají keywords. Začněme s popisem „keywords“. Překlad tohoto slova je poněkud problematický kvůli jeho dvojímu významu (alespoň v programování), takže se pokusím používat sousloví „klíčová hesla“, protože termín „keywords“ v Basilisp neznamená, že by se jednalo o rezervovaná klíčová slova jazyka. Klíčová hesla jsou na použití jednodušší než symboly, protože se ve smyčce REPL vyhodnocují samy na sebe a nemůže jim být přiřazena žádná hodnota.
Zbývá odpovědět na otázku, k jakým účelům se tedy vlastně v praxi tento typ formy hodí? Jedním z důvodů zavedení tohoto typu formy do programovacího jazyka Basilisp byla podpora pro velmi užitečný datový typ (kolekce) nazvaný mapa, ve které je možné uchovávat dvojice klíč:hodnota. A jako klíč jsou s výhodou používána právě klíčová hesla, protože jejich hodnotu nelze měnit a navíc se jejich hešovací hodnota může vypočítat pouze jedenkrát. Smyčka REPL pozná, že uživatel používá klíčové heslo z toho, že je těsně před ním napsána dvojtečka. Jak již bylo řečeno výše, vyhodnotí se heslo na sebe samu (což je odlišné od řetězců, které se v jiných ohledech s hesly v mnoha ohledech podobají):
basilisp.user=> :x :x basilisp.user=> :heslo :symbol basilisp.user=> :dalsi-heslo :dalsi-heslo basilisp.user=> :dalsi.heslo :dalsi.heslo
basilisp.user=> (keyword "heslo") :heslo
basilisp.user=> (doc keyword) ------------------------ basilisp.core/keyword ([name] [ns name]) Create a new keyword with ``name`` and optional namespace ``ns``\. Keywords will have the colon prefix added automatically, so it should not be provided. ``name`` may be keyword, symbol, or string. If ``name`` is a keyword or symbol with a namespace, the namespace will be included in the resulting value. If ``name`` is a string with at least one '/', the string will be split on the first '/' character with the first segment being used as ``ns`` and the second as ``name``. If ``ns`` is not ``nil``, then both ``name`` and ``ns`` must be strings.
Podobným typem formy jsou symboly, před jejichž jménem se používá ampersand. Symbolům může být přiřazena hodnota a z tohoto důvodu se používají pro pojmenování funkcí, proměnných či jmenných prostorů. Se symboly se ještě v tomto článku několikrát setkáme, nyní si tedy jen ukažme, jak se symboly zapisují a jakým způsobem je interaktivní smyčka REPL vyhodnotí:
basilisp.user=> 'symbol symbol basilisp.user=> 'dalsi-symbol dalsi-symbol
Podobně jako dvojtečka byla pouze syntaktickým cukrem pro speciální formu (keyword „xxx“), je i ampersand zkrácenou podobou speciální formy (quote symbol). Předchozí příklad by tedy šel zapsat i následujícím způsobem:
basilisp.user=> (quote symbol) symbol
To, že se v obou případech jedná skutečně o stejný symbol, lze zjistit s využitím funkce ekvivalence (zde již trošku předbíháme, takže se prosím k příkladu vraťte po dočtení celého článku):
basilisp.user=> (= 'symbol (quote symbol)) true
Zatím je to poměrně nuda, že? Ale už se pomalu dostáváme k další dvojici forem – složeným formám a speciálním formám – jejichž vyhodnocování představuje srdce programovacího jazyka Basilisp.
8. Složené formy: strukturované datové typy
V této kapitole si popíšeme takzvané složené formy, protože právě tyto formy představují, společně s formami speciálními, jeden z nejdůležitějších prvků programovacího jazyka Basilisp (a do jisté míry je to podobné i u původního LISPu)). V tradičním LISPu je složenou formou především seznam (list), což je ovšem jen zjednodušeně zapsaný řetězec takzvaných tečka-dvojic. Koncept tečka-dvojic byl v Clojure a tím pádem i v Basilispu opuštěn (samotný znak tečky zde dostal jiný význam – volání metod), ovšem k seznamům navíc přibyly i další způsoby zápisu složených forem, které se používají (opět v podstatě jako syntaktický cukr) pro zápis následujících datových struktur: vektoru (vector), množiny (set) a mapy (map).
Všechny čtyři typy složených forem (budeme je dále nazývat kolekce), ať již se jedná o seznam, vektor, množinu či mapu, jsou při svém zápisu do zdrojového kódu z obou stran uvozeny závorkami, přičemž musí být zachována párovost závorek (ke každé otevírací závorce přísluší jedna závorka uzavírací), která je kontrolována před vyhodnocením složené formy ve smyčce REPL.
V předchozím textu bylo napsáno, že základním typem složené formy je seznam (list), jehož prvky se již tradičně (více než padesát let!) zapisují do kulatých závorek. Pro zápis vektorů (vector) se používají hranaté závorky, mapy (map) využívají závorky složené a množiny (set) taktéž závorky složené, ovšem před otevírací závorkou se musí napsat křížek (hash, #). V následující tabulce jsou vypsány všechny čtyři typy složených forem. Kromě seznamů lze ostatní tři složené formy (vektory, mapy, množiny) vytvořit i pomocí vhodného konstruktoru (třetí sloupec), ovšem přesný význam tohoto zápisu si uvedeme až v následujících kapitolách:
| Typ kolekce | Zápis (syntaktický cukr) | Konstruktor |
|---|---|---|
| Seznam | (prvky) | (list prvky) |
| Vektor | [prvky] | (vector prvky) |
| Mapa | {dvojice klíč-hodnota} | (hash-map dvojice klíč-hodnota) |
| Množina | #{unikátní prvky} | (hash-set unikátní prvky) |
Konstruktory všech čtyř strukturovaných datových typů mají i svoji (velmi stručnou) nápovědu:
basilisp.user=> (doc list) ------------------------ basilisp.core/list ([& args]) Create a list from the arguments. basilisp.user=> (doc vector) ------------------------ basilisp.core/vector ([& elems]) Create a vector from the input arguments. nil basilisp.user=> (doc hash-map) ------------------------ basilisp.core/hash-map ([& kvs]) Create a hash map from pairs of input arguments. nil basilisp.user=> (doc hash-set) ------------------------ basilisp.core/hash-set ([& members]) Create a set from the input arguments. nil
9. Příklady konstrukce kolekcí v programovacím jazyku Basilisp
V tabulce zobrazené v předchozí kapitole byl obsah všech čtyř typů kolekcí popsán jen velmi vágně slovem „prvky“. Z tohoto důvodu bude čtenáře tohoto článku více zajímat, jaké prvky v nich mohou být skutečně uloženy. Může se jednat jak o literály (popsané v předchozích kapitolách), symboly, klíčová hesla, tak i – což je nejzajímavější – o jiné kolekce. Není tedy vůbec neobvyklé pracovat například se seznamy uloženými v jiných seznamech, s mapami (v podstatě se strukturami či záznamy), v nichž jsou uloženy vektory atd. Vzhledem k tomu, že Basilisp je dynamicky typovaným programovacím jazykem, lze v jakémkoli okamžiku získat typ každého prvku uloženého v kolekci. Jak se to ve skutečnosti provádí si vysvětlíme v části věnované predikátům. Podívejme se nyní na několik demonstračních příkladů, kde u každého příkladu bude vysvětleno, co se vlastně provádí a z jakého důvodu Basilisp některý typ formy nedokáže zpracovat.
Před seznamy se musí zapsat znak quote, jinak by došlo k jejich vyhodnocení, jakoby se jednalo o zápis volání funkce. Seznamy pochopitelně mohou být vnořené:
basilisp.user=> '(1 2 3) (1 2 3) basilisp.user=> '(1 2 '(3 '(5 6) 7 8) 9 10) (1 2 (quote (3 (quote (5 6)) 7 8)) 9 10)
Další seznamy:
basilisp.user=> '('toto 'je 'seznam 'symbolů)
((quote toto) (quote je) (quote seznam) (quote symbolů))
basilisp.user=> '("toto" "je" "seznam" "řetězců")
("toto" "je" "seznam" "\u0159et\u011bzc\u016f")
Vektory resp. prvky vektorů se zapisují do hranatých závorek. Zde se naopak znak quote nikdy nepoužívá:
basilisp.user=> [1 2 3] [1 2 3] basilisp.user=> '(1 2 '(3 4 '(5 6) 7 8) 9 10) (1 2 (quote (3 4 (quote (5 6)) 7 8)) 9 10) basilisp.user=> [1 2 [3 4 [5 6] 7 8] 9 10] [1 2 [3 4 [5 6] 7 8] 9 10]
Prázdný seznam a prázdný vektor se zapisuje takto:
basilisp.user=> '() () basilisp.user=> () () basilisp.user=> [] []
Zápis množiny:
basilisp.user=> #{1 2 3 4}
#{1 2 3 4}
Nebo:
basilisp.user=> #{:i :toto :je :množina}
#{:je :toto :i :množina}
Prázdná množina:
basilisp.user=> {}
{}
Pozor ovšem na to, že prvky množiny musí být unikátní:
basilisp.user=> #{1 2 1 3 2 3 3 4}
exception: <class 'basilisp.lang.reader.SyntaxError'>
message: Duplicated values in set: 1, 2, 3
line: 1:18
A konečně se podívejme na zápis slovníku neboli asociativního pole:
basilisp.user=> {:prvni 1 :druhy 2}
{:prvni 1 :druhy 2}
basilisp.user=> {:seznam '(:toto :je :seznam), :vektor [:toto :je :vektor] }
{:seznam (:toto :je :seznam) :vektor [:toto :je :vektor]}
Prázdný slovník:
basilisp.user=> #{}
#{}
Načtení obsahu souboru typu JSON do slovníku (zde nepatrně předbíháme):
basilisp.user=> (import basilisp.json)
basilisp.user=> (basilisp.json/read (open "configuration.json" "r"))
{"llama_stack" {"url" "http://localhost:8321" "api_key" "**********" "use_as_library_client" false "library_client_config_path" nil} "service" {"port" 8080 "access_log" true "auth_enabled" false "tls_config" {"tls_key_password" nil "tls_certificate_path" nil "tls_key_path" nil} "color_log" true "host" "0.0.0.0" "workers" 1} "name" "Lightspeed Core Service (LCS)"}
Ještě nepatrně složitější příklad:
basilisp.user=> (basilisp.pprint/pprint (basilisp.json/read (open "configuration.json" "r")))
{"llama_stack"
{"url" "http://localhost:8321" "api_key" "**********" "use_as_library_client"
false
"library_client_config_path" nil}
"service"
{"port" 8080
"access_log" true
"auth_enabled" false
"tls_config" {"tls_key_password" nil
"tls_certificate_path" nil
"tls_key_path" nil}
"color_log" true
"host" "0.0.0.0"
"workers" 1}
"name" "Lightspeed Core Service (LCS)"}
nil
10. Operace s kolekcemi a nekonečnými sekvencemi
Všechny čtyři typy kolekcí popsaných v předchozích dvou kapitolách, mají několik společných vlastností, které umožňují, aby se v programovacím jazyku Basilisp mohly poměrně snadno vytvářet vícevláknové programy. Základní vlastností společnou všem čtyřem typům kolekcí je jejich neměnitelnost (immutability). To znamená, že již ve chvíli, kdy je kolekce vytvořena, je po celou další dobu její existence v běžícím programu určen její obsah, tj. hodnoty všech prvků kolekce. Na první pohled to sice možná může vypadat zvláštně, ale i s takto se chovajícími kolekcemi je možné v reálným programech pracovat a to dokonce často velmi efektivním způsobem. Ostatně i ve standardní knihovně programovacího jazyka Python existují některé třídy, jejichž instance jsou neměnné. Typickým a všeobecně známým příkladem jsou řetězce představované třídou string.
Kromě neměnitelnosti (immutability) je další společnou vlastností všech čtyř typů kolekcí jejich persistence. Většina standardních funkcí poskytovaná programovacím jazykem Basilisp se totiž snaží o to, aby jednou vytvořené sekvence (dejme tomu seznam) byly znovupoužity i v případě, že je vytvořen nový seznam, který v sobě obsahuje i seznam starší (ten stále existuje a mohou na něj existovat reference používané například i v jiných paralelně či souběžně běžících vláknech).
Vzhledem k tomu, že se obsah starého seznamu nemůže změnit (seznam je neměnitelný), může například funkce cons známá již z LISPu jednoduše k seznamu přidat nový první prvek (head) s tím, že tento prvek ukazuje na původní seznam – jinými slovy není nutné, alespoň v tomto případě, vytvářet kopii (ať již plytkou či hlubokou) původního seznamu, což přispívá k tomu, že mnohé operace nad kolekcemi jsou ve skutečnosti velmi rychlé, i když by se podle jejich popisu mohlo zdát, že jejich implementace vyžaduje provedení časově složitých operací (nebo přesunů bloků dat v paměti).
Podobně funkce pop, kterou skalní LISPaři pravděpodobně znají pod názvem cdr, vrátí „nový“ seznam vytvořený z původního seznamu takovým způsobem, že se z něj „odstraní“ první prvek. Ve skutečnosti se však žádný nový seznam nevytváří a již vůbec se nikde žádný prvek neodstraňuje, pouze se jednoduše vrátí reference na druhý prvek původního seznamu, popř. prázdný seznam (), pokud žádný druhý prvek v seznamu uložen není:
basilisp.user=> (pop [1 2 3]) [1 2]
Podobnou operaci lze provést i s vektory:
basilisp.user=> (pop '(1 2 3)) (2 3)
Další operace s kolekcemi:
basilisp.user=> (peek '(1 2 3)) 1
basilisp.user=> (peek [1 2 3]) 3
S kolekcemi lze pracovat i jako by se jednalo o sekvence:
basilisp.user=> (first '(1 2 3)) 1
basilisp.user=> (first [1 2 3]) 1
Třetí společnou vlastností všech čtyř typů kolekcí je to, že se v každém případě vždy správně vyhodnotí jejich ekvivalence či neekvivalence, nezávisle na tom, jakým způsobem kolekce vznikla. Programovací jazyk Basilisp v tomto případě ovšem nemůže pouze jednoduše porovnat rovnost referencí ukazujících na porovnávané kolekce (například dva seznamy), ale mnohdy musí rekurzivně procházet jak samotnými porovnávanými kolekcemi, tak i jejich prvky, jež taktéž mohou být kolekcemi. Naproti tomu například v Javě to není vždy tak jednoduché, jak by se možná mohlo na první pohled zdát, protože porovnání dvou objektů vyžaduje překrytí metody Object.equals() a tím pádem i detailní znalost interních struktur porovnávaných objektů.
Kolekce lze spojovat do nové kolekce. K tomuto účelu se používají funkce cons (konstruktor) a conj. Ty se od sebe liší podle použité kolekce i pořadím parametrů:
basilisp.user=> (cons 1 [2 3 4]) (1 2 3 4)
basilisp.user=> (conj [1 2 3] 4) [1 2 3 4]
Ovšem u seznamů se výsledky conj liší!:
basilisp.user=> (cons 1 '(2 3 4)) (1 2 3 4)
basilisp.user=> (conj '(1 2 3) 4) (4 1 2 3)
Seznam (kolekce) může vzniknout i jako výsledek dalších operací, například:
Aplikace funkce na všechny prvky zdrojové kolekce:
basilisp.user=> (map inc '(1 2 3 4 5 6 7 8)) (2 3 4 5 6 7 8 9)
Aplikace funkce postupně na všechny n-tice získané ze zdrojových kolekcí:
basilisp.user=> (map * [1 2 3 4] [5 6 7 8]) (5 12 21 32)
Dtto:
basilisp.user=> (map / (range 10) (range 1 10)) (0 1/2 2/3 3/4 4/5 5/6 6/7 7/8 8/9)
Pracovat je možné i s nekonečnými sekvencemi, které se vyhodnocují líně:
basilisp.user=> (doc take) ------------------------ basilisp.core/take ([n] [n coll]) Return the first ``n`` elements of ``coll``\.
Použití této funkce na nekonečné vstupní sekvence:
basilisp.user=> (take 5 (repeat "x"))
("x" "x" "x" "x" "x")
I (range) je generátorem nekonečné sekvence hodnot:
basilisp.user=> (take 10 (range)) (0 1 2 3 4 5 6 7 8 9)
Naproti tomu (range x y) vytváří konečnou sekvenci hodnot:
basilisp.user=> (defn factorial
[n]
(reduce * (range 1 (inc n))))
#'basilisp.user/factorial
basilisp.user=> (factorial 3)
6
basilisp.user=> (factorial 100)
9332621544394415268169923885626670049071
5968264381621468592963895217599993229915
6089414639761565182862536979208272237582
51185210916864000000000000000000000000
Otestování funkce pro výpočet faktoriálu:
basilisp.user=> (dotimes [n 10] (println n (factorial n))) 0 1 1 1 2 2 3 6 4 24 5 120 6 720 7 5040 8 40320 9 362880 nil
11. Predikáty, zjištění typových informací za běhu
Predikáty jsou funkce vracející pravdivostní hodnotu true nebo false. V některých variantách programovacího jazyka LISP bylo zvykem za jméno predikátu dávat znak „p“, takže například funkce/predikát pro test na nulovou hodnotu (velmi často používaný predikát) měl název zerop. V programovacím jazyku Basilisp se namísto znaku „p“ používá otazník, protože i otazník může být součástí názvu identifikátoru. V následující tabulce jsou vypsány základní predikáty:
| # | Predikát | Význam |
|---|---|---|
| 1 | nil? | test, zda je předaná hodnota rovna literálu nil |
| 2 | true? | test, zda je předaná hodnota rovna literálu true |
| 3 | false? | test, zda je předaná hodnota rovna literálu false |
| 4 | number? | test na číslo (libovolného typu) |
| 5 | integer? | test na celé číslo |
| 6 | ratio? | test na zlomek (nikoli na obecné desetinné číslo) |
| 7 | float? | test na desetinné číslo |
| 8 | decimal? | test na hodnotu typu BigDecimal |
| 9 | even? | test na sudou hodnotu |
| 10 | odd? | test na lichou hodnotu |
| 11 | pos? | test na kladnou hodnotu |
| 12 | neg? | test na zápornou hodnotu |
| 13 | zero? | test na nulu |
| 14 | keyword? | test, zda je předaná hodnota typu klíčové heslo |
| 15 | symbol? | test, zda je předaná hodnota typu symbol |
| 16 | char? | test, zda je předaná hodnota typu char |
| 17 | string? | test, zda je předaná hodnota typu řetězec |
| 18 | seq? | test, zda je předaná hodnota typu sekvence |
Příklady volání predikátů:
basilisp.user=> (nil? nil) true basilisp.user=> (nil? '()) false basilisp.user=> (nil? ()) false basilisp.user=> (neg? -42) true basilisp.user=> (neg? 42) false basilisp.user=> (ratio? 1/2) true basilisp.user=> (ratio? 1) false
V některých případech je důležité zjistit typ hodnoty, a to za běhu aplikace. K tomuto účelu lze použít funkci type známou přímo z Pythonu. Příklady volání této funkce:
basilisp.user=> (type nil)
<class 'NoneType'>
basilisp.user=> (type true)
<class 'bool'>
basilisp.user=> (type 'symbol)
<class 'basilisp.lang.symbol.Symbol'>
basilisp.user=> (type :heslo)
<class 'basilisp.lang.keyword.Keyword'>
basilisp.user=> (type '())
<class 'basilisp.lang.list.PersistentList'>
basilisp.user=> (type [])
<class 'basilisp.lang.vector.PersistentVector'>
basilisp.user=> (type #{})
<class 'basilisp.lang.set.PersistentSet'>
basilisp.user=> (type {})
<class 'basilisp.lang.map.PersistentMap'>
12. Řídicí struktury (speciální formy a makra)
Programovací jazyk Basilisp nabízí programátorům několik základních řídicích struktur, které jsou představovány takzvanými speciálními formami (ty se vyhodnocují jinak, než běžné funkce, proto jsou ostatně nazývány „speciální“). Jedná se především o formy se jmény if, loop a recur. Ovšem díky makrosystému, tedy možnosti tvorby uživatelských maker, můžeme v aplikacích psaných v Basilispu použít mnohem více řídicích struktur, které jsou interně postaveny právě na výše zmíněné trojici (celý Basilisp je, podobně jako jeho ideový předchůdce jazyk Clojure, stavebnicí s malým množstvím základních prvků). V následující tabulce jsou vypsány některé z nich (prozatím se soustředíme na rozhodování a rozvětvení toku programu):
| # | Konstrukce | Typ | Stručný popis |
|---|---|---|---|
| 1 | if | speciální forma | základní rozhodovací konstrukce, základ pro další makra |
| 2 | if+do | dvě speciální formy | použito ve chvíli, kdy je nutné do jedné větve či obou větví zapsat více výrazů |
| 3 | if-let | makro | kombinace speciálních forem if a let |
| 4 | if-some | makro | kombinace speciálních forem if (test na nil) a let |
| 5 | and | makro | postupné vyhodnocování předaných výrazů až do chvíle, kdy se vrátí nil či false (jediné „nepravdy“) |
| 6 | or | makro | postupné vyhodnocování předaných výrazů až do chvíle, kdy se vrátí true |
| 7 | when | makro | vhodná náhrada za if s jedinou větví s více výrazy |
| 8 | when-not | makro | vhodná náhrada za if-not s jedinou větví s více výrazy |
| 9 | when-let | makro | kombinace speciálních forem when a let |
| 10 | when-some | makro | kombinace speciálních forem when (test na nil) a let |
| 11 | when-first | makro | použito při testu prvního prvku sekvence s následným zpracováním sekvence |
| 12 | cond | makro | postupné testování podmínek, pokud je podmínka splněna, vrátí se hodnota příslušného výrazu |
| 13 | cond + :else | makro | typické použití makra cond s větví :else nebo :default |
| 14 | condp | makro | postupné dosazování testované hodnoty do zadaného výrazu, obdoba switch-case |
| 15 | cond-> | makro | odvozeno od cond, bude popsáno příště |
| 16 | cond->> | makro | odvozeno od cond, bude popsáno příště |
| 17 | case | makro | další forma realizace rozvětvení |
Pro mnoho z výše uvedených forem je k dispozici i nápověda:
basilisp.user=> (doc if-let) ------------------------ basilisp.core/if-let ([&env &form binding true-cond false-cond]) Evaluate the binding as with ``let``, binding the given name for use in the ``true`` expression iff the binding expression is truthy . Otherwise, return the ``false`` expression without binding the name. nil
basilisp.user=> (doc case) ------------------------ basilisp.core/case ([&env &form expr & clauses]) Switch on ``expr`` to return a matching clause from the set of input clauses. The input expression may be any valid Basilisp expression. A single default expression can follow the clauses, and its value will be returned if no clause matches. The clauses are pairs of a matching value and a return value. The matching values are not evaluated and must be compile-time constants. Symbols will not be resolved. Lists may be passed to match multiple compile time values to a single return value. The dispatch is done in constant time. nil
basilisp.user=> (doc cond->>) ------------------------ basilisp.core/cond->> ([&env &form x & clauses]) Takes a test and form pair, threading ``x`` (as by :lpy:fn:`->>`) through each form for which the corresponding test evaluates as ``true``\. ``cond->>`` does not short circuit evaluation in any case. nil
13. Ukázky využití vybraných řídicích struktur
Všechna makra popsaná v dalším textu jsou založena na využití speciální formy if, jejíž různé varianty si popíšeme v této kapitole.
Nejprve vytvoříme několik jmen navázaných na hodnoty (což je v programovacím jazyku Basilisp obdoba konstant). Tyto hodnoty budou použity v podmínkách uvedených později:
(def x 10) (def y 20) (def z 20)
Základní rozhodovací konstrukce je tvořena speciální formou if, která existuje ve dvou variantách – pouze s větví then a s oběma větvemi then i else. Tuto speciální formu lze tedy zapsat ve zkrácené podobě:
(if test větev-then)
nebo v plné podobě:
(if test větev-then větev-else)
Speciální formu if je možné použít ve formě rozvětvení, což je konstrukce známá například z programovacích jazyků C, Go, Pascalu, Pythonu atd. V tomto případě se (nyní již v Basilisp) typicky setkáme s funkcemi nebo makry s vedlejším efektem, které jsou ve větvi then použity:
(if (< x y) (println "x < y")) x < y nil
V programovacím jazyku Basilisp a současně i ve všech LISPovských programovacích se speciální forma if vyhodnocuje a následně se vrátí výsledek tohoto vyhodnocení. Pokud je podmínka splněna, je vrácena hodnota funkce/makra ve větvi then, v opačném případě je vrácena hodnota funkce/makra ve větvi else nebo nil tehdy, pokud větev else není vůbec zapsána:
(if (< x y) (+ x y)) 30
Nebo ještě jednodušeji:
(if (< x y) :mensi) :mensi
Následující konstrukce vrátí hodnotu nil, protože podmínka není splněna a současně není zapsána větev else:
(if (< y x) (+ x y)) nil
resp:
(if (> x y) :vetsi) nil
Zápis s oběma větvemi:
(if (< x y) (println "x < y") (println "x > y")) x < y nil
Konstrukce if je možné vnořovat:
(if (zero? x)
:nulove
(if (neg? x)
:zaporne
:kladne))
Praktičtější příklad – výpočet největšího společného dělitele:
(defn gcd
[x y]
(if (= x y)
x
(if (> x y)
(gcd (- x y) y)
(gcd x (- y x)))))
(println (gcd 64 24))
8
nil
V tomto případě je však lepší použít konstrukci cond popsanou níže.
Mnohdy se setkáme s požadavkem, že se v jedné větvi speciální formy if popř. v obou větvích má použít více funkcí s vedlejším efektem (volání více funkcí bez vedlejšího efektu nemá význam, i když není zakázáno). Tento požadavek, který je v Algolských programovacích jazycích (C, Pascal, JavaScript, Go, …) vyřešen s využitím programových bloků (složené závorky), by bylo možné otrocky přepsat do jazyka Basilisp pomocí speciální formy do:
(if (< x y)
(do
(println "x < y")
:mensi)
(do
(println "x > y")
:vetsi))
Ve skutečnosti je však výše zmíněná kombinace if + do velmi špatně čitelná, nehledě na to, že se kód začíná ztrácet ve velkém množství kulatých závorek. Existuje však i (pro mnoho účelů) lepší řešení. Pokud konstrukce if obsahuje pouze jedinou větev (předpokládejme nyní pro určité zjednodušení, že se jedná o větev then), lze namísto speciální formy if použít makro nazvané příznačně when:
basilisp.user=> (doc when) ------------------------ basilisp.core/when ([&env &form cond & body]) Evaluate ``cond`` and if it is truthy, execute body in an implicit ``do`` block. nil
Následuje ukázka příkladu použití tohoto makra v situaci, kdy se má při splnění podmínky vykonat více funkcí (s vedlejším efektem) a navíc se má vrátit nějaká hodnota, typicky s využitím funkce bez vedlejšího efektu:
(when (< x y) (println "----------") (println "x < y") (println "----------") :mensi) x < y :mensi
Následuje nepatrně složitější příklad vracející výsledek funkce +:
(when (< x y) (println "----------") (println "x < y") (println "----------") (+ x y)) x < y 30
Blok vykonaný pro opačnou podmínku se zapisuje formou when-not:
basilisp.user=> (doc when-not) ------------------------ basilisp.core/when-not ([&env &form cond & body]) Evaluate ``cond`` and if it is falsey, execute body in an implicit ``do`` block. nil
14. Konstrukce cond a condp
Všechny rozhodovací konstrukce popsané v předchozí kapitole prováděly rozvětvení toku programu na základě vyhodnocení jediné podmínky. Ovšem v praxi se velmi často setkáme s nutností rozhodovat se na základě většího množství podmínek popř. na základě většího množství hodnot (a obecně pak na základě pattern matchingu, což si ukážeme příště). Pokud je nutné provést rozhodnutí na základě více podmínek, nabízí se využití makra nazvaného cond, které se mj. objevilo (i když jinak zapisované) už v prvních verzích LISPu:
basilisp.user=> (doc cond) ------------------------ basilisp.core/cond ([&env &form & clauses]) Given groups of test/expression pairs, evaluate each test and, if ``true``\, return the expression. Otherwise, continue through until reaching the final expression. nil
Tomuto makru se předávají dvojice test+výraz. Pokud je test splněn, je vrácena hodnota příslušného výrazu. Poslední test bývá zapsán formou symbolu, který se vždy vyhodnotí na pravdu – což je vlastně jakýkoli symbol rozdílný od false nebo nil. Typicky se používá symbol :else, ovšem někteří vývojáři dávají přednost :default (takže se jedná o céčkaře nebo Javisty :-).
Funkci pro výpočet znaménka lze s využitím makra cond přepsat následujícím způsobem:
(defn sgn-3
[x]
(cond (pos? x) 1
(neg? x) -1
true 0))
Otestování funkcionality takto upravené funkce je snadné:
(doseq [value [-100 -1 0 1 100]]
(println (sgn-3 value)))
Se shodnými výsledky, jako tomu bylo v předchozích příkladech:
-1 -1 0 1 1
Poslední test se ovšem většinou zapisuje symbolem :else:
(defn sgn-4
[x]
(cond (pos? x) 1
(neg? x) -1
:else 0))
nebo :default:
(defn sgn-5
[x]
(cond (pos? x) 1
(neg? x) -1
:default 0))
Přepis funkce pro výpočet největšího společného dělitele:
(defn gcd-2
[x y]
(cond
(= x y) x
(> x y) (gcd-2 (- x y) y)
:else (gcd-2 x (- y x))))
S otestováním:
(println (gcd-2 64 24)) 8 nil (println (gcd-2 123456 6543216)) 48 nil
Pokusme se nyní výraz s makrem cond expandovat, abychom zjistili, jaký kód bude vlastně přeložen do bajtkódu:
(macroexpand
'(cond (pos? x) 1
(neg? x) -1
:else 0))
Výsledkem expanze bude:
(if (pos? x) 1 (basilisp.core/cond (neg? x) -1 :else 0))
Plná expanze makra:
basilisp.user=> (macroexpand-all
'(cond (pos? x) 1
(neg? x) -1
:else 0))
Výsledek už bude obsahovat jen vnořenou speciální formu if:
(if (pos? x) 1 (if (neg? x) -1 (if :else 0 nil)))
Pro zajímavost si vyzkoušejme expanzi složitějšího výrazu, který převádí bodové ohodnocení na známky:
(let [grade 85]
(cond
(>= grade 90) "A"
(>= grade 80) "B"
(>= grade 70) "C"
(>= grade 55) "D"
:else "F"))
Expanze:
basilisp.user=> (macroexpand
'(cond
(>= grade 90) "A"
(>= grade 80) "B"
(>= grade 70) "C"
(>= grade 55) "D"
:else "F"))
Výsledek:
(if (>= grade 90) "A" (basilisp.core/cond (>= grade 80) "B" (>= grade 70) "C" (>= grade 55) "D" :else "F"))
Plná expanze"
basilisp.user=> (macroexpand-all
'(cond
(>= grade 90) "A"
(>= grade 80) "B"
(>= grade 70) "C"
(>= grade 55) "D"
:else "F"))
Výsledek bude opět obsahovat jen vnořenou speciální formu if:
(if (>= grade 90) "A" (if (>= grade 80) "B" (if (>= grade 70) "C" (if (>= grade 55) "D" (if :else "F" nil)))))
Výše popsané makro cond je velmi univerzální, protože každý test (kterých může být libovolné množství) je realizován plnohodnotným predikátem, tj. funkcí, na základě jejíž (pravdivostní) návratové hodnoty se rozhoduje, jestli se má provést příslušná větev či zda se má vyzkoušet další test. Ve výsledku je toto makro expandováno na vnořené speciální formy if. Ovšem mnohdy takovou univerzálnost nepotřebujeme a naopak vyžadujeme, aby se výsledek nějakého výrazu porovnal se sekvencí známých hodnot. Taková konstrukce, která je v C, C++ či Javě realizována přes switch, se v programovacím jazyku Basilisp zapisuje s využitím makra nazvaného condp:
basilisp.user=> (doc condp) ------------------------ basilisp.core/condp ([&env &form pred expr & clauses]) Take a predicate and an expression and a series of clauses, call ``(pred test expr)`` on the first expression for each clause. The result expression from first the set of clauses for which this expression returns a truthy value will be returned from the ``condp`` expression. Clauses can take two forms: - ``test-expr result-expr`` - ``test-expr :>> result-fn`` where :>> is a keyword literal For the ternary expression clause, the unary ``result-fn`` will be called with the result of the predicate. A single final expression can be included at the end with no test expression which will be returned if no other clause matches the predicate. If no default is provided and no clause matches the predicate, a ``ValueError`` will be thrown. nil
Z popisu je zřejmé, že je nutné uvést část výrazu, do kterého se postupně doplňují hodnoty z testů v jednotlivých větvích – skutečně se tedy jedná o obdobu case z C či Javy. Poslední větev pochopitelně žádnou hodnotu pro otestování neobsahuje.
Podívejme se nyní na základní způsob použití tohoto makra. Na základě předaného řetězce se rozhodneme, jaká hodnota se vrátí (jedná se o primitivní transformaci, která by se v reálném programu realizovala přes mapu):
(let [value (read-line)]
(condp = value
"one" 1
"two" 2
"three" 3
"four" 4
"five" 5
"unknown value"))
Samozřejmě namísto konstant ve větvích můžeme použít nějaký složitější výraz, zde konkrétně volání funkcí +, – atd:
(let [value (read-line)]
(condp = value
"one" (+ 0 1)
"two" (+ 1 1)
"three" 3
"four" (* 2 2)
"five" 5
(str "unexpected value, \"" value \")))
Výrazy mohou být použity i v testovaných hodnotách (což představuje rozdíl oproti některým výše zmíněným programovacím jazykům):
(let [value (read-line)]
(condp = value
"one" (+ 0 1)
(str "t" "wo") (+ 1 1)
(str "t" "ree") 3
"four" (* 2 2)
"five" 5
(str "unexpected value, \"" value \")))
Expanze condp:
basilisp.user=> (macroexpand-all '(let [value (read-line)]
(condp = value
"one" 1
"two" 2
"three" 3
"four" 4
"five" 5
"unknown value")))
Výsledkem je konstrukce postavená na speciální formě if:
(let* [value (.rstrip (.readline *in*))]
(if (= "one" value)
1
(if (= "two" value)
2
(if (= "three" value)
3
(if (= "four" value)
4
(if (= "five" value)
5
"unknown value"))))))
15. Balíčky dodávané se samotným jazykem Basilisp
Společně s Basilispem jsou dodávány i některé balíčky, jejichž jména a do značné míry i obsah je inspirován jazykem Clojure. To zjednodušuje portaci programů, protože vlastně postačuje změnit první hodnotu ve jmenném prostoru z clojure na basilisp:
| Jmenný prostor |
|---|
| basilisp.contrib.bencode |
| basilisp.contrib.nrepl-server |
| basilisp.core |
| basilisp.core.protocols |
| basilisp.data |
| basilisp.edn |
| basilisp.io |
| basilisp.json |
| basilisp.main |
| basilisp.pprint |
| basilisp.process |
| basilisp.repl |
| basilisp.set |
| basilisp.shell |
| basilisp.stacktrace |
| basilisp.string |
| basilisp.template |
| basilisp.test |
| basilisp.test.fixtures |
| basilisp.url |
| basilisp.walk |
Příklad použití funkce z balíčku basilisp.pprint:
basilisp.user=> (use 'basilisp.pprint)
basilisp.user=> (pprint (macroexpand-all '(let [value (read-line)]
(condp = value
"one" 1
"two" 2
"three" 3
"four" 4
"five" 5
"unknown value"))))
(let*
[value (.rstrip (.readline *in*))]
(if
(= "one" value)
1
(if
(= "two" value)
2
(if
(= "three" value)
3
(if
(= "four" value)
4
(if (= "five" value) 5 "unknown value"))))))
nil
16. Interoperabilita s Pythonem
Nejdůležitějším rysem Basilispu je jeho schopnost relativně snadno volat kód psaný v Pythonu. Bez této schopnosti by se jednalo „jen“ o další interpret LISPu, kterých vzniklo několik set. Ovšem fakt, že Basilisp může volat jakoukoli funkci Pythonu (z libovolného balíčku) nebo metodu jakékoli třídy, vlastně otevírá celý rozsáhlý ekosystém Pythonu světu LISPu.
Ukažme si tuto schopnost na několika příkladech. Nejdříve načteme standardní Pythonovský balíček datetime (způsobem importu se budeme podrobněji zabývat v další kapitole):
basilisp.user=> (import datetime) nil
Zavolání funkce now vracející objekt. Do konzole se vypíše tisknutelná podoba tohoto objektu:
basilisp.user=> (datetime.datetime/now) #inst "2025-11-11T16:18:25.492381"
Objekt (tedy instanci třídy) si můžeme uložit do nové proměnné nazvané například now:
basilisp.user=> (def now (datetime.datetime/now)) #'basilisp.user/now
Ověření, že pracujeme s typem „objekt“:
basilisp.user=> (type now) <class 'datetime.datetime'>
Můžeme získat i seznam atributů a metod, což není překvapivé, protože dir je původní funkce z Pythonu:
basilisp.user=> (dir now) #py ["__add__" "__class__" "__delattr__" "__dir__" "__doc__" "__eq__" "__format__" "__ge__" "__getattribute__" "__getstate__" "__gt__" "__hash__" "__init__" "__init_subclass__" "__le__" "__lt__" "__ne__" "__new__" "__radd__" "__reduce__" "__reduce_ex__" "__repr__" "__rsub__" "__setattr__" "__sizeof__" "__str__" "__sub__" "__subclasshook__" "astimezone" "combine" "ctime" "date" "day" "dst" "fold" "fromisocalendar" "fromisoformat" "fromordinal" "fromtimestamp" "hour" "isocalendar" "isoformat" "isoweekday" "max" "microsecond" "min" "minute" "month" "now" "replace" "resolution" "second" "strftime" "strptime" "time" "timestamp" "timetuple" "timetz" "today" "toordinal" "tzinfo" "tzname" "utcfromtimestamp" "utcnow" "utcof
Přístup k atributu objektu se provádí možná poněkud neobvykle s využitím lomítka (převzato z Clojure):
basilisp.user=> now/year 2025
Pro volání metody se používá speciální forma zapisovaná tečkou, což je opět neobvyklé:
basilisp.user=> (. now __str__) "2025-11-11 16:19:00.366118"
Metodu je ovšem možné volat i jako běžnou (pseudo)funkci s tečkou na začátku. Prvním parametrem je instance třídy:
basilisp.user=> (.__str__ now) "2025-11-11 16:19:00.366118"
Ukázka volání metody, která akceptuje další parametry:
basilisp.user=> (. now strftime "%Y-%m-%d") "2025-11-11"
Alternativní způsob zápisu:
basilisp.user=> (.strftime now "%Y-%m-%d") "2025-11-11"
Ještě si musíme ukázat, jak se volají standardní funkce Pythonu, které se jmenují stejně, jako funkce v Basilispu. Příkladem je funkce str:
basilisp.user=> (str 42) "42"
Původní Pythonovskou funkci str musíme uvést i se jmenným prostorem:
basilisp.user=> (python/str 42) "42"
Složitější příklad, kde se kombinují standardní funkce Pythonu i standardní funkce Basilispu:
basilisp.user=> (python/str (abs (int "-42"))) "42"
Mimochodem: je zde možné s výhodou použít threading macro (možná se jedná o jeden z nejlepších způsobů, jak se zbavovat závorek ve zdrojových kódech :-):
basilisp.user=> (-> "-42" int abs python/str) "42"
17. Využití balíčků Pythonu přímo z Basilispu
Z Basilispu je možné volat i funkce z naimportovaných standardních Pythonovských balíčků, popř. přistupovat k proměnným, které jsou v těchto balíčcích definovány.
Balíček je nejdříve nutné naimportovat, a to například následujícím způsobem:
basilisp.user=> (import json) nil
Poté je možné volat funkce, které jsou v tomto balíčku definovány, a to s využitím konvence (jmenný_prostor/jméno_funkce):
basilisp.user=> (json/dumps (dict {"foo" 1 "bar" 2}))
"{\"foo\": 1, \"bar\": 2}"
Naimportujeme ještě jeden balíček, nyní math:
basilisp.user=> (import math) nil
Přečtení hodnoty proměnné definované v balíčku (bez závorek, protože nechceme volat funkci):
basilisp.user=> math/pi 3.141592653589793
Zavolání funkce z tohoto balíčku:
basilisp.user=> (math/sqrt 2) 1.4142135623730951
Alternativně je možné definovat jmenný alias, podobně jako je tomu i v samotném Pythonu:
basilisp.user=> (import [math :as m]) nil
Přístup k funkci přes jmenný alias:
basilisp.user=> (m/sqrt 2) 1.4142135623730951
Funkce a proměnné (resp. přesněji řečeno symboly) můžeme zařadit přímo do aktuálního jmenného prostoru:
basilisp.user=> (import [math :refer [pi sqrt]]) nil
Poté se již neuvádí jmenný prostor:
basilisp.user=> pi 3.141592653589793
Nebo:
basilisp.user=> (sqrt 2) 1.4142135623730951
18. Předchozí části seriálu o LISPovských programovacích jazycích
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, odkazy na tento seriál jsou uvedeny na konci kapitoly):
- 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/ - Common Lisp: žralok mezi programovacími jazyky
https://www.root.cz/clanky/common-lisp-zralok-mezi-programovacimi-jazyky/ - Common Lisp: žralok mezi programovacími jazyky (2.část)
https://www.root.cz/clanky/common-lisp-zralok-mezi-programovacimi-jazyky-2-cast/ - 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/
Č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/
Seriál o programovacím jazyku Clojure:
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v azyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - Novinky v Clojure verze 1.9.0
https://www.root.cz/clanky/novinky-v-clojure-verze-1–9–0/ - Validace dat s využitím knihovny spec v Clojure 1.9.0
https://www.root.cz/clanky/validace-dat-s-vyuzitim-knihovny-spec-v-clojure-1–9–0/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure/ - Použití jazyka Gherkin při tvorbě testovacích scénářů pro aplikace psané v Clojure (2)
https://www.root.cz/clanky/pouziti-jazyka-gherkin-pri-tvorbe-testovacich-scenaru-pro-aplikace-psane-v-nbsp-clojure-2/ - Incanter: prostředí pro statistické výpočty s grafickým výstupem založené na Clojure
https://www.root.cz/clanky/incanter-prostredi-pro-statisticke-vypocty-s-grafickym-vystupem-zalozene-na-clojure/ - Incanter: operace s maticemi
https://www.root.cz/clanky/incanter-operace-s-maticemi/ - Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
https://www.root.cz/clanky/interpret-programovaciho-jazyka-clojure-integrovany-do-jupyter-notebooku/ - Babashka: interpret Clojure určený pro rychlé spouštění utilit z příkazového řádku
https://www.root.cz/clanky/babashka-interpret-clojure-urceny-pro-rychle-spousteni-utilit-z-prikazoveho-radku/ - Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw/ - Pokročilý streaming založený na Apache Kafce, jazyku Clojure a knihovně Jackdaw (2. část)
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-apache-kafce-jazyku-clojure-a-knihovne-jackdaw-2-cast/ - Pokročilý streaming založený na projektu Apache Kafka, jazyku Clojure a knihovně Jackdaw (streamy a kolony)
https://www.root.cz/clanky/pokrocily-streaming-zalozeny-na-projektu-apache-kafka-jazyku-clojure-a-knihovne-jackdaw-streamy-a-kolony/ - Řídicí struktury využitelné v programovacím jazyku Clojure
https://www.root.cz/clanky/ridici-struktury-vyuzitelne-v-programovacim-jazyku-clojure/
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, Barbara Kaiser, Karl Knight
„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 - Graham Hutton
A tutorial on the universality andexpressiveness of fold
http://www.cs.nott.ac.uk/~pszgmh/fold.pdf
20. Odkazy na Internetu
- Hy 1.0.0: dialekt Lispu integrovaný do Pythonu
https://www.root.cz/zpravicky/hy-1–0–0-dialekt-lispu-integrovany-do-pythonu/ - Janet Language
https://janet-lang.org/ - Janet na GitHubu
https://github.com/janet-lang/janet - Janet for Mortals (a real book)
https://janet.guide/ - Bauble studio
https://bauble.studio/ - Janet na Hacker News
https://news.ycombinator.com/item?id=34843306 - 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 - 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/ - Grafický metaformát PostScript
https://www.root.cz/clanky/graficky-metaformat-postscript/ - Vektorový grafický formát SVG
https://www.root.cz/clanky/vektorovy-graficky-format-svg/ - The Racket Drawing Toolkit
https://docs.racket-lang.org/draw/index.html - 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 - SICP (The Structure and Interpretation of Computer Programs)
http://mitpress.mit.edu/sicp/ - Pure function
http://en.wikipedia.org/wiki/Pure_function - Funkcionální programování
http://cs.wikipedia.org/wiki/Funkcionální_programování - Jazyky Hy a Clojure-py: moderní dialekty LISPu určené pro Python VM
https://www.root.cz/clanky/jazyky-hy-a-clojure-py-moderni-dialekty-lispu-urcene-pro-python-vm/ - Pixie: lehký skriptovací jazyk s „kouzelnými“ schopnostmi
https://www.root.cz/clanky/pixie-lehky-skriptovaci-jazyk-s-kouzelnymi-schopnostmi/ - Programovací jazyk Pixie: funkce ze základní knihovny a použití FFI
https://www.root.cz/clanky/programovaci-jazyk-pixie-funkce-ze-zakladni-knihovny-a-pouziti-ffi/ - The Nature of Lisp
https://defmacro.org/ramblings/lisp.html - Stránka projektu Jython
http://www.jython.org/ - Jython (Wikipedia)
https://en.wikipedia.org/wiki/Jython - Scripting for the Java Platform (Wikipedia)
https://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - JSR 223: Scripting for the JavaTM Platform
https://jcp.org/en/jsr/detail?id=223 - List of JVM languages
https://en.wikipedia.org/wiki/List_of_JVM_languages - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - Economy Size Geek – Interview with Rich Hickey, Creator of Clojure
https://www.linuxjournal.com/article/10708 - Pyrsistent: persistentní datové struktury v Pythonu
https://www.root.cz/clanky/pyrsistent-persistentni-datove-struktury-v-pythonu/ - Pyrsistent: persistentní datové struktury v Pythonu (dokončení)
https://www.root.cz/clanky/pyrsistent-persistentni-datove-struktury-v-pythonu-dokonceni/