Projekt Gambit – další kvalitní interpret i překladač programovacího jazyka Scheme

15. 12. 2020
Doba čtení: 52 minut

Sdílet

Existuje přibližně 50 použitelných implementací jazyka Scheme, ovšem jen zhruba patnáct implementací je skutečně vhodných pro produkční nasazení. Mezi nejkvalitnější implementace Scheme patří projekt nazvaný Gambit.

Obsah

1. Projekt Gambit – další kvalitní interpret i překladač programovacího jazyka Scheme

2. Transpřekladače; interaktivní smyčka REPL

3. Gambit se představuje

4. Instalace projektu Gambit

5. Interpret a překladač – gsi a gsc

6. Použití interpretru dodávaného současně s Gambitem

7. Debugger, který je součástí REPLu

8. Základní vlastnosti jazyka Scheme

9. Rozšíření zavedená (nejenom) systémem Gambit – nepovinné parametry funkcí

10. Další možnosti volání funkcí

11. Definice nových datových typů (struktur)

12. Příprava jednoduchého benchmarku

13. Porovnání rychlosti interpretrů Gambit, GNU Guile a Chicken Scheme

14. Rychlost benchmarku přeloženého do nativního kódu

15. Přepis algoritmu takovým způsobem, aby používal výpočty s hodnotami s plovoucí řádovou čárkou

16. Použití vláken, paralelizace výpočtů

17. Porovnání všech benchmarků

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

19. Literatura

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

21. Odkazy na Internetu

1. Projekt Gambit – další kvalitní interpret i překladač programovacího jazyka Scheme

„Scheme is simple, weird, and cool.“

„My God, It's full of 'car's“

Jak jsme se již zmínili v perexu dnešního článku, existuje v současnosti přibližně padesát reálně použitelných implementací programovacího jazyka Scheme, ať již se jedná o interpretry či o překladače. Pokud však budeme hledat skutečně kvalitní a stabilní implementaci vhodnou pro produkční nasazení (a i když se to může zdát divné, Scheme skutečně bývá takto nasazováno, i když se z různých důvodů jedná o málo známá řešení), zmenšuje se počet vhodných systémů postavených nad jazykem Scheme na zhruba patnáct, přičemž jednotlivé vhodné projekty můžeme podle použitých technologií rozdělit do několika skupin:

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

V dnešním článku se zaměříme na třetí zmíněnou skupinu, konkrétně na projekt Gambit-C či zkráceně jen Gambit. Tento projekt obsahuje jak již zmíněný transpřekladač, tak i interpret doplněný o interaktivní programovou smyčku REPL neboli Read-Eval-Print-Loop (REPL je podle mého názoru jedním z nejdůležitějších vynálezů v oblasti IT – zdaleka se totiž nemusí jednat o pouhou interaktivní příkazovou řádku, což ostatně ukazuje popularita projektů založených na diářích, například Jupyter Notebooku).

2. Transpřekladače; interaktivní smyčka REPL

Poznámka: tato kapitola je krátkou odbočkou s popisem dvou technologií, s nimiž se v souvislosti s Gambit setkáme. Jedná se o technologii transpřekladačů a taktéž o koncept interaktivní smyčky REPL.

V úvodní kapitole jsme se mj. zmínili i o problematice takzvaných transpřekladačů (transcompilers, source-to-source compilers). Připomeňme si, že transpřekladače jsou (dosti obecně řečeno) nástroje sloužící pro překlad algoritmů zapsaných v nějakém zdrojovém programovacím jazyce do zvoleného cílového jazyka (ovšem nikoli do nativního kódu, mezikódu – intermetidate code – či bajtkódu, to je totiž role běžných překladačů).

Transpřekladače se v informatice používají již po několik desetiletí; například se stále můžeme setkat s nástroji, které převádí kód z nějakého vyššího programovacího jazyka do Céčka, které je dnes s trochou nadsázky chápáno jako „univerzální assembler“. Asi nejznámějším příkladem staršího použití transpřekladačů je nástroj nazvaný web2c, jenž slouží pro transformaci zdrojových kódů TeXu do céčka. Transpřekladače se stávají velmi populární i pro programátory webových aplikací, a to zejména z toho důvodu, že webové prohlížeče nativně podporují většinou pouze JavaScript, který je tak přirozeně cílovým jazykem transpřekladačů (proto se také JavaScriptu někdy říká „assembler pro web“).

Z praxe můžeme uvést například následující projekty založené na transpřekladači:

# Jazyk či transpřekladač Poznámka
1 CoffeeScript přidání syntaktického cukru do JavaScriptu
2 ClojureScript překlad aplikací psaných v Clojure do JavaScriptu
3 TypeScript nadmnožina jazyka JavaScript, přidání datových typů
4 6to5 transpřeklad z ECMAScript 6 (nová varianta JavaScriptu) do starší varianty JavaScriptu
5 Kaffeine rozšíření JavaScriptu o nové vlastnosti
6 RedScript jazyk inspirovaný Ruby
7 GorillaScript další rozšíření JavaScriptu
8 ghcjs transpřekladač pro fanoušky programovacího jazyka Haskell
9 Haxe transpřekladač, mezi jehož cílové jazyka patří i Java a JavaScript
10 Wisp transpřekladač jazyka podobného Clojure, opět do JavaScriptu
11 ScriptSharp transpřekladač z C# do JavaScriptu
12 Dart transpřekladač z jazyka Dart do JavaScriptu
13 COBOL → C transpřekladač OpenCOBOL
14 COBOL → Java transpřekladač P3COBOL
15 lua2js transpřekladač jazyka Lua, opět do JavaScriptu
16 Coconut transpřekladač jazyka Coconut do Pythonu

I s principem a použitím interaktivní smyčky REPL jsme se již na stránkách Rootu setkali, a to dokonce mnohokrát. Kromě článků, které se věnovaly klasickým Unixovým shellům typu BASH, tcsh či zsh (a rozhraní shellů není nic jiného, než interaktivní REPL), jsme smyčku REPL použili například při popisu programovacího jazyka Julia či jazyka Clojure. Historií vzniku REPL jsme se zabývali i zde.

Některé smyčky REPL jsou pojaty přísně minimalisticky, což je případ dnes již spíše méně často používaného jazyka TCL. Tato interaktivní REPL dokonce ani neobsahuje historii příkazů či podporu pro pohyb kurzoru na příkazovém řádku:

%
Poznámka: povšimněte si, že se liší i znak výzvy (prompt), protože se namísto obvyklého > používá znak procenta; to je ovšem pouze marginální změna.

Další interaktivní REPL alespoň uživatele informují, v jakém prostředí se nachází. To je případ REPL (opět velmi jednoduše pojaté) programovacího jazyka Lua:

Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
>

REPL projektu LuaJIT vypadá nepatrně odlišně:

LuaJIT 2.1.0-beta3 -- Copyright (C) 2005-2017 Mike Pall. http://luajit.org/
JIT: ON SSE2 SSE3 SSE4.1 BMI2 fold cse dce fwd dse narrow loop abc sink fuse
>

Nově se plnohodnotný REPL objevil i v jazyku Clojure; v předchozích verzích se používal dále zmíněný alternativní nREPL:

Clojure 1.9.0
user=>

Podobně vypadá REPL programovacího jazyka Pixie (to vlastně není nijak překvapivé, protože se opět jedná o jednu z v:

user =>

Interaktivní rozhraní projektu GNU Guile, což je jedna z variant programovacího jazyka Scheme:

GNU Guile 2.0.14
Copyright (C) 1995-2016 Free Software Foundation, Inc.
 
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
 
Enter `,help' for help.
scheme@(guile-user)>

Plnohodnotnou smyčku REPL se všemi vymoženostmi nabízí zejména programovací jazyk Julia, což ostatně není překvapivé, protože se tento jazyk používá právě pro postupnou inkrementální tvorbu aplikací v interaktivním prostředí:

               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.0.0 (2018-08-08)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |
 
julia>

Podobně je tomu v případě programovacího jazyka Clojure doplněného o nREPL (ten lze spustit například příkazem lein repl):

nREPL server started on port 42733 on host 127.0.0.1 - nrepl://127.0.0.1:42733
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
OpenJDK 64-Bit Server VM 1.8.0_171-b10
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e
 
user=>

Samozřejmě nesmíme zapomenout ani na REPL doménově specifického jazyka R:

R version 3.5.3 (2019-03-11) -- "Great Truth"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-redhat-linux-gnu (64-bit)
 
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.
 
  Natural language support but running in an English locale
 
R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.
 
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
 
During startup - Warning messages:
1: Setting LC_TIME failed, using "C"
2: Setting LC_MONETARY failed, using "C"
3: Setting LC_PAPER failed, using "C"
4: Setting LC_MEASUREMENT failed, using "C"
gt;

Obrázek 1: Jedna z alternativních REPL určených pro programovací jazyk Python.

A v neposlední řadě nalezneme REPL i v systému Gambit, jemuž se věnujeme v dnešním článku:

$ gsi
Gambit v4.8.8
 
>

Obrázek 2: Za zjednodušenou formu interaktivní smyčky REPL je možné považovat i takzvaný přímý mód (direct mode) použitý například v klasickém BASICu. Na tomto screenshotu je v přímém módu zapsán příkaz LIST.

3. Gambit se představuje

Projekt Gambit má za sebou poměrně velmi dlouhý vývoj, protože jeho existenci můžeme vysledovat až do roku 1989, tedy 31 let do minulosti. V té době vznikl první překladač (tedy nikoli ještě transpřekladač) jazyka Scheme generující strojový kód pro slavný mikroprocesor Motorola 68000 (M68k). Tehdy obsahoval Gambit skutečně pouze překladač, nikoli interpret. Dokonce, což je zvláštní, se v runtime zpočátku ani nenacházel systém pro automatickou správu paměti (garbage collector), což je pro LISPovský programovací jazyk spíše výjimka.

Poznámka: samotný LISP, z něhož byl jazyk Scheme odvozen, je ovšem ještě starší. Jeho koncept vznikl již v roce 1958.
lisp01

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

Historie systému Gambit-C resp. později Gambit v kostce:

  • 1989: první překladač pro mikroprocesor M68K, prozatím bez interprertru a bez GC
  • 1991: MacGambit pro platformu Apple Macintosh
  • 1994: první backend pro C, použití Gambitu v komerční sféře
  • 2004: Gambit v4, podpora vláken, podporuje LGPL i Apache Licenci

Původním cílem Gambitu bylo zajistit kompatibilitu s R5RS. Dále bylo naplánováno vytvořit systém přenositelný na různé platformy s generátorem velmi rychlého a současně i malého výsledného binárního kódu. Dnes se s tímto systémem setkáme ve výzkumu, při převodu (transpilaci) Scheme do céčka (což si popíšeme dnes), JavaScriptu či do VHDL a Gambit je dostupný i pro embedded systémy (obraz může být menší než 20kB a stále kompatibilní alespoň s R4RS). Již méně často se Gambit používá jako skriptovací jazyk vkládaný do aplikací; to je dnes doménou GNU Guile.

4. Instalace projektu Gambit

Poznámka: ve skutečnosti si můžeme základní vlastnosti systému Gambit otestovat na adrese https://feeley.github.io/gambit-in-the-browser/, v níž Gambit REPL běží v prohlížeči.

Gambit je dostupný ve formě balíčku pro různé varianty Linuxu, takže mnohdy ani není nutné stahovat a překládat zdrojové kódy. Instalace na postarší (dnes již vlastně historické) Fedoře 27:

$ sudo dnf install gambit-c
 
Last metadata expiration check: 0:09:50 ago on Sat 04 Jul 2020 08:05:09 PM CEST.
Dependencies resolved.
================================================================================
 Package           Arch            Version                Repository       Size
================================================================================
Installing:
 gambit-c          x86_64          4.8.8-3.fc27           fedora          6.3 M
 
Transaction Summary
================================================================================
Install  1 Package
 
Total download size: 6.3 M
Installed size: 41 M
Is this ok [y/N]:

Průběh instalace:

Downloading Packages:
gambit-c-4.8.8-3.fc27.x86_64.rpm                1.9 MB/s | 6.3 MB     00:03
--------------------------------------------------------------------------------
Total                                           1.3 MB/s | 6.3 MB     00:04
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                        1/1
  Installing       : gambit-c-4.8.8-3.fc27.x86_64                           1/1
  Running scriptlet: gambit-c-4.8.8-3.fc27.x86_64                           1/1
Running as unit: run-r04b3ce47d8fc449e97c9e1ae9a102764.service
  Verifying        : gambit-c-4.8.8-3.fc27.x86_64                           1/1
 
Installed:
  gambit-c.x86_64 4.8.8-3.fc27
 
Complete!

Instalace na Fedoře 32 (včetně překladače C a linkeru):

$ sudo dnf install gambit-c
 
Dependencies resolved.
================================================================================
 Package           Arch     Version            Repository                  Size
================================================================================
Installing:
 gambit-c          x86_64   4.9.3-3.fc32       beaker-Fedora-Everything   6.0 M
Installing dependencies:
 binutils          x86_64   2.34-6.fc32        updates                    5.4 M
 binutils-gold     x86_64   2.34-6.fc32        updates                    852 k
 cpp               x86_64   10.2.1-6.fc32      updates                    9.4 M
 gcc               x86_64   10.2.1-6.fc32      updates                     30 M
 glibc-devel       x86_64   2.31-4.fc32        updates                    1.0 M
 glibc-headers     x86_64   2.31-4.fc32        updates                    457 k
 isl               x86_64   0.16.1-10.fc32     beaker-Fedora-Everything   872 k
 kernel-headers    x86_64   5.9.13-100.fc32    updates                    1.2 M
 libmpc            x86_64   1.1.0-8.fc32       beaker-Fedora-Everything    59 k
 libxcrypt-devel   x86_64   4.4.17-1.fc32      updates                     32 k
 
Transaction Summary
================================================================================
Install  11 Packages
 
Total download size: 55 M
Installed size: 191 M

Instalace na Linux Mintu (pozor na odlišné jméno balíčku):

$ sudo apt-get install install gambc
 
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  gambc-doc libgambit4 libgambit4-dev
The following NEW packages will be installed:
  gambc gambc-doc libgambit4 libgambit4-dev
0 upgraded, 4 newly installed, 0 to remove and 399 not upgraded.
Need to get 593 kB/3 101 kB of archives.
After this operation, 21,7 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
 
ading package lists... Done
 
Setting up gambc-doc (4.8.8-3.1) ...
Setting up libgambit4:amd64 (4.8.8-3.1) ...
Setting up libgambit4-dev:amd64 (4.8.8-3.1) ...
Setting up gambc (4.8.8-3.1) ...
update-alternatives: using /usr/bin/gsi to provide /usr/bin/scheme-r5rs (scheme-r5rs) in auto mode
Processing triggers for libc-bin (2.31-0ubuntu9) ...
Processing triggers for man-db (2.9.1-1) ...
Processing triggers for install-info (6.7.0.dfsg.2-5) ...
Processing triggers for doc-base (0.10.9) ...
Processing 1 added doc-base file...

5. Interpret a překladač – gsi a gsc

Gambit může být použit jak v režimu interpretru, tak i překladače. Interpret se spouští příkazem gsi. Z uživatelského pohledu se jedná o klasickou interaktivní smyčku REPL. Na rozdíl od Guile ve výchozím nastavení (pokud explicitně neinicializujete modul s readline) je možné pracovat s historií příkazů, používat kurzorové šipky, všechny základní editační příkazy známé z BASHe (záleží na .inputrc) atd.:

Obrázek 4: Interaktivní smyčka REPL spuštěná příkazem gsi.

Informace o konfiguraci interpretru v době jeho překladu zjistíme snadno:

$ gsi -v
 
v4.8.8 20170202123920 x86_64-redhat-linux-gnu "./configure
'--build=x86_64-redhat-linux-gnu' '--host=x86_64-redhat-linux-gnu'
'--program-prefix=' '--disable-dependency-tracking' '--prefix=/usr'
'--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin'
'--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include'
'--libdir=/usr/lib64' '--libexecdir=/usr/libexec' '--localstatedir=/var'
'--sharedstatedir=/var/lib' '--mandir=/usr/share/man'
'--infodir=/usr/share/info' '--enable-single-host' '--enable-c-opt'
'--enable-gcc-opts' '--bindir=/usr/lib64/gambit-c/bin'
'--libdir=/usr/lib64/gambit-c' 'build_alias=x86_64-redhat-linux-gnu'
'host_alias=x86_64-redhat-linux-gnu' 'CFLAGS=-O2 -g -pipe -Wall
-Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
-fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic'
'LDFLAGS=-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld'
'CXXFLAGS=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2
-fexceptions -fstack-protector-strong --param=ssp-buffer-size=4
-grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64
-mtune=generic'"

Překladač Gambitu se spouští příkazem gsc:

$ gsc -exe factorial_3.scm 
 
$ ./factorial_3
3628800
Poznámka: překlad (což je ve skutečnosti transpřeklad a následné zavolání gcc a linkeru) je velmi rychlý, což je jeden z obrovských praktických rozdílů mezi Gambitem a Clojure (s Leiningenem):
$ time gsc -exe factorial_3.scm
 
real    0m0.427s
user    0m0.375s
sys     0m0.048s

Lze se podívat i na přesnější informace o tom, jaké operace se při překladu provádí:

$ gsc -exe -verbose factorial_3.scm
 
Parsing:
  print
  factorial
  "expr"
 
Compiling:
  print
factorial
fact-iter
 
Dumping:
  #<primitive | factorial_3|>
  #<procedure print>
  #<procedure factorial>
 
Compilation finished.
gcc -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic   -Wno-unused -Wno-write-strings -O2 -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -fmodulo-sched -freschedule-modulo-scheduled-loops -fomit-frame-pointer -fPIC -fno-common -mieee-fp -mpc64   -D___SINGLE_HOST  -I"/usr/include" -c -o "factorial_3.o"  factorial_3.c
gcc -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic   -Wno-unused -Wno-write-strings -O2 -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -fmodulo-sched -freschedule-modulo-scheduled-loops -fomit-frame-pointer -fPIC -fno-common -mieee-fp -mpc64   -D___SINGLE_HOST  -I"/usr/include" -c -o "factorial_3_.o"  factorial_3_.c
gcc -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic   -Wno-unused -Wno-write-strings -O2 -fwrapv -fno-strict-aliasing -fno-trapping-math -fno-math-errno -fschedule-insns2 -fmodulo-sched -freschedule-modulo-scheduled-loops -fomit-frame-pointer -fPIC -fno-common -mieee-fp -mpc64   -rdynamic  -D___SINGLE_HOST  -I"/usr/include"  -o "factorial_3"   factorial_3.o factorial_3_.o "/usr/lib64/gambit-c/libgambit.a" -lutil -ldl -lm

Opět můžeme zjistit, jaké přepínače a konfigurační volby byly použity při jeho vlastním překladu:

$ gsc -v
 
v4.8.8 20170202123920 x86_64-redhat-linux-gnu "./configure
'--build=x86_64-redhat-linux-gnu' '--host=x86_64-redhat-linux-gnu'
'--program-prefix=' '--disable-dependency-tracking' '--prefix=/usr'
'--exec-prefix=/usr' '--bindir=/usr/bin' '--sbindir=/usr/sbin'
'--sysconfdir=/etc' '--datadir=/usr/share' '--includedir=/usr/include'
'--libdir=/usr/lib64' '--libexecdir=/usr/libexec' '--localstatedir=/var'
'--sharedstatedir=/var/lib' '--mandir=/usr/share/man'
'--infodir=/usr/share/info' '--enable-single-host' '--enable-c-opt'
'--enable-gcc-opts' '--bindir=/usr/lib64/gambit-c/bin'
'--libdir=/usr/lib64/gambit-c' 'build_alias=x86_64-redhat-linux-gnu'
'host_alias=x86_64-redhat-linux-gnu' 'CFLAGS=-O2 -g -pipe -Wall
-Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions
-fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches
-specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic'
'LDFLAGS=-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld'
'CXXFLAGS=-O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2
-fexceptions -fstack-protector-strong --param=ssp-buffer-size=4
-grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64
-mtune=generic'"

6. Použití interpretru dodávaného současně s Gambitem

Interpret spouštěný příkazem gsi se v mnoha ohledech podobá interpretru GNU Guile. Zadávané příkazy (resp. přesněji řečeno se jedná o formy a speciální příkazy) jsou vykonány ihned poté, co je forma ukončena a je stisknuta klávesa Enter. To znamená, že lze zadávat i víceřádkové formy, což jsme si ukázali v předchozí kapitole na příkladu faktoriálu. Při zápisu forem se navíc provádí „doskoky“ na právě uzavřené závorky, což je u LISPovského jazyka užitečné. Důležité jsou ovšem i speciální příkazy, kterými se ovládá vlastní REPL, popř. debugger, který je součástí REPLu. Tyto příkazy začínají čárkou, což znamená, že s objekty, jejichž název začíná taktéž čárkou (což Scheme umožňuje), se bude pracovat obtížně (ovšem kdo by používal takové identifikátory?).

Seznam všech dostupných příkazů REPLu získáme pomocí příkazy ,? (což je odlišné od GNU Guile!):

> ,?
 
,?              : Summary of comma commands
,h   | ,(h X)   : Help on procedure of last error or procedure/macro named X
,q              : Terminate the process
,qt             : Terminate the current thread
,t              : Jump to toplevel REPL
,d              : Jump to enclosing REPL
,c   | ,(c X)   : Continue the computation with stepping off
,s   | ,(s X)   : Continue the computation with stepping on (step)
,l   | ,(l X)   : Continue the computation with stepping on (leap)
,N              : Move to specific continuation frame (N>=0)
,N+  | ,N-      : Move forward/backward by N continuation frames (N>=0)
,+   | ,-       : Like ,1+ and ,1-
,++  | ,--      : Like ,N+ and ,N- with N = nb. of frames at head of backtrace
,y              : Display one-line summary of current frame
,i              : Display procedure attached to current frame
,b   | ,(b X)   : Display backtrace of current continuation or X (cont/thread)
,be  | ,(be X)  : Like ,b and ,(b X) but also display environment
,bed | ,(bed X) : Like ,be and ,(be X) but also display dynamic environment
,e   | ,(e X)   : Display environment of current frame or X (proc/cont/thread)
,ed  | ,(ed X)  : Like ,e and ,(e X) but also display dynamic environment
,st  | ,(st X)  : Display current thread group, or X (thread/thread group)
,(v X)          : Start a REPL visiting X (proc/cont/thread)

7. Debugger, který je součástí REPLu

Nejdůležitější je podpora pro zjišťování problémů, které nastaly při běhu skriptů – jedná se tedy o základní debugging. Můžeme si to vyzkoušet na příkladu, který obsahuje chybu ve výpočtu:

(define (print item)
  (display item)
  (newline))
 
(define (factorial n)
  (if (= n 0) ; podmínka pro ukončení rekurzivního zanořování
      (/ n 0) ; chyba ve výpočtu
      (* n (factorial (- n 1)))
      )
  )

Skript nejdříve načteme:

> (load "factorial_error.scm")
 
"/home/ptisnovs/src/lisp-families/gambit/factorial_error.scm"

Zkusíme spustit výpočet, při němž dojde k chybě:

> (factorial 10)
*** ERROR IN factorial, "factorial_error.scm"@8.14 -- Divide by zero
(/ 0 0)

K chybě došlo až hluboko v rekurzivním výpočtu, takže se pokusíme získat další informace příkazem ,b:

1> ,b
 
0  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
1  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
2  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
3  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
4  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
5  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
6  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
7  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
8  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
9  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
10 (interaction)                                     (console)@2:1                                     (factorial 10)

Podrobnější informace o tom, s jakými parametry byly funkce volány v rekurzivním výpočtu:

2> ,be
 
0  (interaction)                                     (console)@4:33                                    x
        n = 1
1  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 1
2  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 2
3  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 3
4  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 4
5  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 5
6  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 6
7  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 7
8  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 8
9  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 9
10 factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 10
11 (interaction)                                     (console)@2:1                                     (factorial 10)

A konečně se můžeme v zásobníkových rámcích pohybovat a dostat se přesně na tu oblast, kterou je zapotřebí více prozkoumat:

2> ,bed
 
0  (interaction)                                     (console)@4:33                                    x
        n = 1
        (current-exception-handler) = primordial-exception-handler
        (current-input-port) = '#<input-output-port #2 (console)>
        (current-output-port) = '#<input-output-port #2 (console)>
        (current-directory) = "/home/ptisnovs/src/other/lisp-families/gambit/"
1  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 1
        (current-exception-handler) = primordial-exception-handler
        (current-input-port) = '#<input-output-port #2 (console)>
        (current-output-port) = '#<input-output-port #2 (console)>
        (current-directory) = "/home/ptisnovs/src/other/lisp-families/gambit/"
2  factorial                                         "factorial_error.scm"@8:14                        (factorial (- n 1))
        n = 2
        (current-exception-handler) = primordial-exception-handler
        (current-input-port) = '#<input-output-port #2 (console)>
        (current-output-port) = '#<input-output-port #2 (console)>
        (current-directory) = "/home/ptisnovs/src/other/lisp-families/gambit/"
 
2> ,2+
 
2  factorial                                         "factorial_error.scm"@8.14                        (factorial (- n 1))

8. Základní vlastnosti jazyka Scheme

Gambit podporuje všechny vlastnosti popsané v R4RS i R5RS, takže jen v krátkosti (většinu příkladů jsme již viděli s výjimkou continuations a práci s výjimkami).

Práce s tečka-dvojicemi:

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

Konstrukce seznamů:

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

Přístup k prvkům seznamů:

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

Standardní predikáty:

(define nil '())
 
(print "pair?")
(print (pair? nil))
(print (pair? #t))
(print (pair? 42))
(print (pair? "string"))
(print (pair? '(1 2 3)))
(newline)
 
(print "list?")
(print (list? nil))
(print (list? #t))
(print (list? 42))
(print (list? "string"))
(print (list? '(1 2 3)))
(newline)
 
(print "null?")
(print (null? nil))
(print (null? #t))
(print (null? 42))
(print (null? "string"))
(print (null? '(1 2 3)))
(newline)
 
(print "zero?")
(print (zero? 0))
(print (zero? 42))
(newline)

Blok begin s formami, které se postupně vykonávají:

(begin
  (print "pair?")
  (print (pair? nil))
  (print (pair? #t))
  (print (pair? 42))
  (print (pair? "string"))
  (print (pair? '(1 2 3)))
  (newline))
 
(begin
  (print "list?")
  (print (list? nil))
  (print (list? #t))
  (print (list? 42))
  (print (list? "string"))
  (print (list? '(1 2 3)))
  (newline))
 
(begin
  (print "null?")
  (print (null? nil))
  (print (null? #t))
  (print (null? 42))
  (print (null? "string"))
  (print (null? '(1 2 3)))
  (newline))
 
(begin
  (print "zero?")
  (print (zero? 0))
  (print (zero? 42))
  (newline))

Logické operace a použití speciálních forem and a or namísto if:

(define nil '())
 
(print (and #t #t))
(print (and #t nil))
(print (or #t #t))
(print (or #t nil))
(print (or nil nil #t nil))
(print (or nil nil nil nil))
(print (not nil))
(print (not #t))
 
(define x 10)
(print (if (> x 0) "kladne" "zaporne"))
 
(define y 0)
(print (if (> y 0) "kladne" "zaporne"))
 
(define x 10)
(print (and (> x 0) "kladne"))
 
(define y 0)
(print (and (> y 0) "kladne"))

Speciální forma cond zobecňující rozeskoky:

(define (sgn n)
  (cond
    ((< n 0)      'negative)
    ((> n 0)      'positive)
    ((zero? n)    'zero)))
 
(print "sgn")
(print (sgn -10))
(print (sgn 0))
(print (sgn 10))
(newline)
 
 
(define (sgn-2 n)
  (cond
    ((< n 0)      'negative)
    ((> n 0)      'positive)
    (#t           'zero)))
 
(print "sgn-2")
(print (sgn-2 -10))
(print (sgn-2 0))
(print (sgn-2 10))
(newline)
 
(define (sgn n)
  (cond
    ((not (number? n)) 'not-a-number)
    ((< n 0)      'negative)
    ((> n 0)      'positive)
    ((zero? n)    'zero)))
 
(print (sgn -10))
(print (sgn 0))
(print (sgn 10))
 
(print (sgn '()))

Konstrukce vektorů, přístup k prvkům vektorů:

(define vector1 '#(1 2 3 4))
 
(display vector1)
(newline)
 
(display (vector-ref vector1 0))
(display (vector-ref vector1 10))

Mutace prvků vektorů:

(define vector2 (vector 1 2 3 4 5))
 
(display vector2)
(newline)
 
(display (vector-ref vector2 0))
(newline)
 
(vector-set! vector2 2 -1)
 
(display vector2)
(newline)

Anonymní funkce:

(lambda () (print "no parameters"))
 
(lambda (a) (print "one parameter"))
 
(lambda (a b) (print "two parameters"))
 
(lambda (a . b) (print "at least one parameter"))
 
(lambda (a b . c) (print "at least two parameters"))
 
(lambda x (print "zero or more parameters"))

Pojmenované funkce:

; one-liner function
(define (add x y) (+ x y))
 
; function written on more lines
(define (mul x y)
  (* x y))
 
; function written on more lines using lambda
(define div (lambda (x y)
  (* x y)))
 
; test functions
(print (add 1 2))
(print (mul 6 7))
(print (div 10 3))

Uzávěry:

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

Více nezávislých čítačů:

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

Použití quote a quasiquote (nejenom) při konstrukci seznamů:

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

Novinkou (resp. ne zcela běžnou věcí) je zachytávání výjimek, které je ukázáno na příkladu s funkcí, která nevyhodí výjimku při dělení nulou. Namísto toho vrátí #f, což je výsledek anonymní funkce akceptující objekt s chybou:

(define (safe-div x y)
  (with-exception-catcher
    (lambda (error) #f)
    (lambda () (/ x y))))
 
(print (safe-div 10 3))
(print (safe-div 10 0))

A poslední ne vždy implementovanou vlastností jsou takzvané continuations (pokračování), což je obecně velmi užitečná programovací technika, kterou si vysvětlíme v samostatném článku:

(define c1 #f)
 
(define (test-cc)
  (let ((i 0))
    (call/cc (lambda (k) (set! c1 k)))
    (set! i (+ i 1))
    i))

9. Rozšíření zavedená (nejenom) systémem Gambit – nepovinné parametry funkcí

Gambit, podobně jako některé další varianty jazyka Scheme, umožňuje volání funkcí s proměnným počtem parametrů, popř. s nepovinnými parametry. Funkce s nepovinnými parametry se používají následovně:

(define (f1)
  (print "no parameters"))
 
(define (f2 a)
  (print "one parameter")
  (print a))
 
(define (f3 a b)
  (print "two parameters")
  (print a)
  (print b))
 
(define (f4 a #!optional b)
  (print "at least one parameter")
  (print a)
  (print b))
 
(define (f5 a b #!optional c)
  (print "at least two parameters")
  (print a)
  (print b)
  (print c))
 
(define (f6 a #!optional (b -1))
  (print "at least one parameter")
  (print a)
  (print b))
 
(define (f7 a b #!optional (c -1))
  (print "at least two parameters")
  (print a)
  (print b)
  (print c))
 
(f1)
(f2 10)
(f3 1 2)
(f4 1)
(f4 1 2)
(f5 1 2)
(f5 1 2 3)
(f6 1)
(f6 1 2)
(f7 1 2)
(f7 1 2 3)

S výsledky:

no parameters
one parameter
10
two parameters
1
2
at least one parameter
1
#f
at least one parameter
1
2
at least two parameters
1
2
#f
at least two parameters
1
2
3
at least one parameter
1
-1
at least one parameter
1
2
at least two parameters
1
2
-1
at least two parameters
1
2
3
Poznámka: povšimněte si, že u nepovinných parametrů je možné zadat jejich výchozí hodnotu (parametr i hodnota musí být v samostatné závorce). Pokud výchozí hodnota není uvedena, použije se namísto ní #f.

10. Další možnosti volání funkcí

Použití proměnného počtu parametrů – zbylé parametry se uloží do seznamu za tečkou:

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

Výsledky:

no parameters
one parameter
10
two parameters
1
2
at least one parameter
1
()
at least one parameter
1
(2)
at least one parameter
1
(2 3)
at least two parameters
1
2
()
at least two parameters
1
2
(3)
at least two parameters
1
2
(3 4)

Pojmenované parametry:

(define (f b #!key c (d 7) (e 8))
  (print b)
  (print c)
  (print e)
  (print e)
  (newline))
 
(f 0)
(f 1 c: 2)
(f 1 e: 5)
(f 1 c: 2 d: 3 e: 4)

Výsledky:

0
#f
8
8
 
1
2
8
8
 
1
#f
5
5
 
1
2
4
4

A konečně kombinace nepovinných parametrů a tzv.„rest“ (zbývajících) parametrů:

(define (f1 #!optional (a 4) #!key (b 5) c)
  (print a)
  (print b)
  (print c)
  (newline))
 
(define (f2 #!key (i 5) #!rest j)
  (print i)
  (print j)
  (newline))
 
(f1)
(f1 1)
(f1 2 b: 3)
(f1 4 b: 5 c: 6)
(f1 7 c: 8)
(f2 9)
(f2 10 i: 11)
(f2 i: 12 13)

11. Definice nových datových typů (struktur)

S využitím formy define-type je možné definovat tvar nové datové struktury, pro kterou se navíc automaticky vytvoří konstruktor, funkce pro přístup k prvkům struktury (gettery), funkce pro modifikaci prvků struktury (settery, mutátory) i predikáty pro nový datový typ. Podívejme se nyní na jednoduchý příklad s datovou strukturou pojmenovanou user s prvky nazvanými name a surname. Po zavolání define-type se vytvoří konstruktor make-user, gettery user-name a user-surname i mutátory user-name-set! a user-surname-set!. Zapomenout nesmíme ani na predikát user?:

(define (print item)
  (display item)
  (newline))
 
(define-type user name surname)
 
; konstruktor
(define john (make-user "John" "?"))
(print john)
 
; gettery
(print (user-name john))
(print (user-surname john))
 
; mutatory (settery)
(user-name-set! john "Real John")
(user-surname-set! john "Doe")
(print john)
(print (user-name john))
(print (user-surname john))
 
; predikaty
(print (user? 42))
(print (user? john))

Příklad použití:

#<user #2 name: "John" surname: "?">
John
?
#<user #2 name: "Real John" surname: "Doe">
Real John
Doe
#f
#t

12. Příprava jednoduchého benchmarku

V úvodních kapitolách jsme si řekli, že projekt Gambit může být pro vývojáře zajímavý mj. i proto, že je vybaven rychlým a plnohodnotným překladačem. Zkusme tedy zjistit, jak kvalitní kód tento překladač dokáže generovat; provedeme přitom porovnání s již dříve popsanými implementacemi programovacího jazyka Scheme, tedy zejména s GNU Guile a Chicken Scheme. Pro tento účel si připravíme jednoduchý benchmark, s nímž jsme se vlastně již seznámili v předchozích článcích. Jedná se o program určený pro iterativní výpočet konstanty π s využitím (velmi pomalu konvergujícího) Wallisova součinu (Wallis product, který je popsán například na stránce https://en.wikipedia.org/wi­ki/Wallis_product). Jeden z možných přepisů tohoto algoritmu do Scheme může vypadat následovně:

(define (compute-pi n)
  (let ((pi 4.0))
    (do ((i 3 (+ i 2)))
      ((> i (+ n 2)))
      (set! pi (* pi (/ (- i 1) i) (/ (+ i 1) i))))
    pi))
 
(do ((n 1 (* n 2)))
  ((> n 10000000))
  (display n)
  (display " ")
  (display (compute-pi n))
  (newline))
Poznámka: využíváme zde spíše imperativního přístupu a nikoli přístupu funkcionálního. To je patrné zejména v použití forem do, které jsou ovšem pro programy psané ve Scheme většinou dosti netypické. Funkcionální tvar by mohl vypadat takto:
(define (compute-pi n)
  (let loop ((pi 4.0)
             (i 3))
    (if (<= i (+ n 2))
        (loop (* pi (/ (- i 1) i) (/ (+ i 1) i))
              (+ i 2))
        pi)))
 
(let loop ((n 1))
  (display n)
  (display " ")
  (display (compute-pi n))
  (newline)
  (if (<= n 10000000)
      (loop (* n 2))))

Výše uvedený benchmark použijeme v následujících kapitolách pro otestování kvality či nekvality výsledného kódu generovaného Gambitem-C.

Pro porovnání přepíšeme benchmark i do jazyka Clojure:

(ns pi-1.core
  (:gen-class))
 
(defn compute-pi
  [n]
  (loop [pi 4.0
         i  3]
         (if (< i (+ n 2))
             (recur (* pi (/ (- i 1) i) (/ (+ i 1) i))
                    (+ i 2))
             pi)))
 
(defn -main
  [& args]
  (loop [n 1]
    (print n "\t")
    (println (compute-pi n))
    (if (< n 5000000)
      (recur (* n 2)))))

13. Porovnání rychlosti interpretrů Gambit, GNU Guile a Chicken Scheme

S projektem nazvaným GNU Guile jsme se již v tomto seriálu seznámili. Jedná se o interpret jazyka Scheme doplněný o JIT překladač, takže můžeme předpokládat, že by výpočetní výkon takto doplněného interpretru mohl být vyšší, než je tomu v případě jednoduchého interpretru dodávaného s projektem Chicken Scheme. Ostatně se o tomto předpokladu můžeme snadno přesvědčit, protože výše popsaný výpočet konstanty π je napsán takovým způsobem, že je kompatibilní jak s GNU Guile, tak i s Gambitem a Chicken Scheme (ovšem pozor – ne všechny konstrukce je možné mezi těmito implementacemi Scheme bez problémů přenášet i přesto, že je zachována kompatibilita s RnRS).

Nejprve tedy výpočet spustíme v GNU Guile a budeme sledovat jak strojový čas strávený výpočtem, tak i celkový čas viditelný vnějším pozorovatelem (což je mnohdy důležitější ukazatel):

$ time guile pi1.scm

Výsledky, na jejichž konci jsou zobrazeny i časové údaje:

1 3.5555555555555554
2 3.5555555555555554
4 3.4133333333333336
8 3.302393550012597
16 3.230036466411716
32 3.1881271694471383
64 3.1654820600347926
128 3.1536988490957967
256 3.147686899556418
512 3.1446501625172
1024 3.143124017028185
2048 3.142358989121772
4096 3.141975985005608
8192 3.1417843602347433
16384 3.1416885171495856
32768 3.1416405879293077
65536 3.1416166213993866
131072 3.1416046376544267
262144 3.1415986456618494
524288 3.141595649635512
1048576 3.141594151614876
2097152 3.141593402602468
4194304 3.1415930280955355
8388608 3.1415928408418403
 
real    0m4.858s
user    0m5.212s
sys     0m0.058s
Poznámka: povšimněte si, že čas strávený výpočtem je z pohledu uživatele cca 4,8 sekundy (real=čas, který je možné změřit stopkami vně počítače), zatímco z pohledu mikroprocesoru je čas delší – celých 5,70 sekund (user+sys). To znamená, že některé výpočty musely být provedeny ve více vláknech, což je ostatně jen dobře.

Nyní si vyzkoušejme, jestli bude výpočet π podle stejného skriptu s využitím interpretru nástroje Chicken Scheme rychlejší nebo pomalejší. Použijeme přepínače -b a -q, které zajistí, že se interpret po dokončení výpočtů ihned ukončí a že se na začátku nebudou zobrazovat úvodní informace o projektu Chicken Scheme (což sice nevede k žádnému podstatnému urychlení, ale ke zpřesnění výsledných časů):

$ time csi -b -q pi1.scm

Samotné výsledky výpočtu by měly být přibližně podobné, minimálně na prvních sedmi až osmi desetinných místech:

1 3.55555555555556
2 3.55555555555556
4 3.41333333333333
8 3.3023935500126
16 3.23003646641172
32 3.18812716944714
64 3.16548206003479
128 3.1536988490958
256 3.14768689955642
512 3.1446501625172
1024 3.14312401702818
2048 3.14235898912177
4096 3.14197598500561
8192 3.14178436023474
16384 3.14168851714959
32768 3.14164058792931
65536 3.14161662139939
131072 3.14160463765443
262144 3.14159864566185
524288 3.14159564963551
1048576 3.14159415161488
2097152 3.14159340260247
4194304 3.14159302809554
8388608 3.14159284084184
 
real    0m8.137s
user    0m7.739s
sys     0m0.318s

Čas celého výpočtu je v tomto případě výrazně delší, než tomu je v porovnání s projektem GNU Guile. Dále můžeme při porovnání všech tří časů předpokládat, že výpočet běžel pouze v jediném vláknu (což je ostatně pravda).

Nakonec vyzkoušíme stejný výpočet (a naprosto stejný zdrojový kód) spustit v intepretru Gambitu:

$ time gsi pi_1.scm

Výsledky:

1 3.5555555555555554
2 3.5555555555555554
4 3.4133333333333336
8 3.302393550012597
16 3.230036466411716
32 3.1881271694471383
64 3.1654820600347926
128 3.1536988490957967
256 3.147686899556418
512 3.1446501625172
1024 3.143124017028185
2048 3.142358989121772
4096 3.141975985005608
8192 3.1417843602347433
16384 3.1416885171495856
32768 3.1416405879293077
65536 3.1416166213993866
131072 3.1416046376544267
262144 3.1415986456618494
524288 3.141595649635512
1048576 3.141594151614876
2097152 3.141593402602468
4194304 3.1415930280955355
8388608 3.1415928408418403
 
real    0m46.689s
user    0m46.610s
sys     0m0.007s

Stručné porovnání výsledků:

# Interpret real user sys
1 GNU Guile 4,858 5,212 0,058
2 Chicken Scheme 8,137 7,738 0,318
3 Gambit (gsi) 46,689 46,610 0,007
Poznámka: vidíme, že interpret Gambitu v žádném případě není rychlejší, než je tomu v GNU Guile a Chicken Scheme.

14. Rychlost benchmarku přeloženého do nativního kódu

Nyní se pokusme náš testovací příklad přeložit a zjistit, jak a zda došlo k urychlení výpočtů:

$ gsc -exe pi_1.scm 

Pokud se překlad povedl, spustíme benchmark:

$ time ./pi_1

Výsledky:

real    0m37.454s
user    0m37.390s
sys     0m0.008s
Poznámka: po překladu sice dosáhneme určitého urychlení výpočtů, ovšem stále je výsledek přeloženého programu pomalejší, než v případě interpretrů GNU Guile či Chicken Scheme!

15. Přepis algoritmu takovým způsobem, aby používal výpočty s hodnotami s plovoucí řádovou čárkou

Algoritmus je možné v případě potřeby ještě vyššího výpočetního výkonu přepsat takovým způsobem, aby se výpočty prováděly s hodnotami s plovoucí řádovou čárkou. To se zajistí jak deklarací mostly-flonum užitečné pro překladač, tak i použitím operátorů fl*, fl/ a fl+ namísto operátorů *, / a +:

(declare
  (mostly-flonum)
  (block)
  (not safe))
 
(define (compute-pi n)
  (let ((pi 4.0))
    (do ((i 3.0 (fl+ i 2.0)))
      ((fl> i (fl+ n 2.0)))
      (set! pi (fl* pi (fl/ (fl- i 1.0) i) (fl/ (fl+ i 1.0) i))))
    pi))
  
(do ((n 1.0 (* n 2)))
  ((> n 10000000))
  (display n)
  (display " ")
  (display (compute-pi n))
  (newline))

Výsledek běhu interpretru (gsi):

1. 3.5555555555555554
2. 3.5555555555555554
4. 3.4133333333333336
8. 3.302393550012597
16. 3.230036466411716
32. 3.1881271694471383
64. 3.1654820600347926
128. 3.1536988490957967
256. 3.147686899556418
512. 3.1446501625172
1024. 3.143124017028185
2048. 3.142358989121772
4096. 3.141975985005608
8192. 3.1417843602347433
16384. 3.1416885171495856
32768. 3.1416405879293077
65536. 3.1416166213993866
131072. 3.1416046376544267
262144. 3.1415986456618494
524288. 3.141595649635512
1048576. 3.141594151614876
2097152. 3.141593402602468
4194304. 3.1415930280955355
8388608. 3.1415928408418403

Čas dosažený při interpretaci:

real    0m8.188s
user    0m8.169s
sys     0m0.008s

Ještě si vyzkoušíme rychlost výpočtu po překladu, kde by se měly plně projevit optimalizace při překladu:

$ gsc -exe pi_3_flonum.scm 

Výsledky výpočtů:

$ time ./pi_3_flonum
 
1. 3.5555555555555554
2. 3.5555555555555554
4. 3.4133333333333336
8. 3.302393550012597
16. 3.230036466411716
32. 3.1881271694471383
64. 3.1654820600347926
128. 3.1536988490957967
256. 3.147686899556418
512. 3.1446501625172
1024. 3.143124017028185
2048. 3.142358989121772
4096. 3.141975985005608
8192. 3.1417843602347433
16384. 3.1416885171495856
32768. 3.1416405879293077
65536. 3.1416166213993866
131072. 3.1416046376544267
262144. 3.1415986456618494
524288. 3.141595649635512
1048576. 3.141594151614876
2097152. 3.141593402602468
4194304. 3.1415930280955355
8388608. 3.1415928408418403

Dosažený čas:

real    0m0.153s
user    0m0.141s
sys     0m0.011s
Poznámka: zde jsme již dosáhli znatelného urychlení, což znamená, že Gambit může být při pečlivém naprogramování užitečný. Ovšem pokračujme dále.

16. Použití vláken, paralelizace výpočtů

Jednou z předností Gambitu je relativně jednoduchá paralelizace výpočtů (i když ne tak jednoduchá, jako by tomu bylo v případě použití gorutin a kanálů). V runtime lze výpočty upravit takovým způsobem, aby počet vláken odpovídal počtu procesorových jader. Existuje přitom funkce nazvaná ##cpu-count vracející počet reálně dostupných jader a taktéž funkce current-vm-processor-count vracející počet vláken OS, které lze využít (s tím, že mapování vláken na CPU je ponecháno na operačním systému).

Vytvoření vlákna zajistí forma make-thread, které se předá kód, který se má spustit. Spuštění vlákna se provede s využitím thread-start!, čekání na dokončení vlákna pak pomocí thread-join!. Podívejme se nyní, jak lze předchozí kód paralelizovat i s akumulací výsledků:

; původní funkce pro výpočet se nemusí měnit
(define (compute-pi n)
  (let ((pi 4.0))
    (do ((i 3 (+ i 2)))
      ((> i (+ n 2)))
      (set! pi (* pi (/ (- i 1) i) (/ (+ i 1) i))))
    pi))
 
; pomocná funkce pro výpočet a zobrazení výsledků
(define (pi-for n)
  (let ((pi (compute-pi n)))
      (display n)
      (display "\t")
      (display pi)
      (newline)))
 
; vytvoření seznamu se vstupními hodnotami n
(define (power-of-two n maximum)
  (if (< n maximum)
     (cons n (power-of-two (* n 2) maximum))
     (list n)))
 
; vytvoření výpočetních vláken
(define threads (map (lambda (n) (make-thread (lambda () (pi-for n))))
                     (power-of-two 1 5000000)))
 
; spuštění všech vláken
(for-each thread-start! threads)
 
; čekání na dokončení výpočtů ve všech vláknech
(for-each thread-join!  threads)

Čas výpočtů:

$ time ./pi_parallel
 
1       3.5555555555555554
2       3.5555555555555554
4       3.4133333333333336
8       3.302393550012597
16      3.230036466411716
32      3.1881271694471383
64      3.1654820600347926
128     3.1536988490957967
256     3.147686899556418
512     3.1446501625172
1024    3.143124017028185
2048    3.142358989121772
4096    3.141975985005608
8192    3.1417843602347433
16384   3.1416885171495856
32768   3.1416405879293077
65536   3.1416166213993866
131072  3.1416046376544267
262144  3.1415986456618494
524288  3.141595649635512
1048576 3.141594151614876
2097152 3.141593402602468
4194304 3.1415930280955355
8388608 3.1415928408418403
 
real    0m36.867s
user    0m36.800s
sys     0m0.013s
Poznámka: tato úloha není plně paralelizovatelná.

Paralelní verze s flonum:

(declare
  (mostly-flonum)
  (block)
  (not safe))
 
(define (compute-pi n)
  (let ((pi 4.0))
    (do ((i 3.0 (fl+ i 2.0)))
      ((fl> i (fl+ n 2.0)))
      (set! pi (fl* pi (fl/ (fl- i 1.0) i) (fl/ (fl+ i 1.0) i))))
    pi))
 
(define (pi-for n)
  (let ((pi (compute-pi n)))
    (display n)
    (display "\t")
    (display pi)
    (newline)))
 
(define (power-of-two n maximum)
  (if (< n maximum)
      (cons n (power-of-two (* n 2) maximum))
      (list n)))
 
(define threads (map (lambda (n) (make-thread (lambda () (pi-for n))))
                     (power-of-two 1.0 5000000)))
 
(for-each thread-start! threads)
(for-each thread-join!  threads)

Výsledek výpočtu po překladu:

$ time ./pi_parallel_flonum
 
1.        3.5555555555555554
2.        3.5555555555555554
4.        3.4133333333333336
8.        3.302393550012597
16.       3.230036466411716
32.       3.1881271694471383
64.       3.1654820600347926
128.      3.1536988490957967
256.      3.147686899556418
512.      3.1446501625172
1024.     3.143124017028185
2048.     3.142358989121772
4096.     3.141975985005608
8192.     3.1417843602347433
16384.    3.1416885171495856
32768.    3.1416405879293077
65536.    3.1416166213993866
131072.   3.1416046376544267
262144.   3.1415986456618494
524288.   3.141595649635512
2097152.  3.141593402602468
1048576.  3.141594151614876
4194304.  3.1415930280955355
8388608.  3.1415928408418403
 
real    0m0.159s
user    0m0.150s
sys     0m0.009s

V Clojure bude paralelní výpočet vypadat takto:

(ns pi-2.core
  (:gen-class))
 
(defn compute-pi
  [n]
  (loop [pi 4.0
         i  3]
         (if (< i (+ n 2))
             (recur (* pi (/ (- i 1) i) (/ (+ i 1) i))
                    (+ i 2))
             pi)))
 
(def power-of-2
  (iterate (partial *' 2) 2))
 
(defn -main
  [& args]
  (let [ns (take-while (partial > 10000000) power-of-2)
        pi (pmap compute-pi ns)
        result (map vector ns pi)]
    (doseq [r result]
      (println (first r) "\t" (nth r 1))))
  (shutdown-agents))

17. Porovnání všech benchmarků

V této kapitole budou všechny benchmarky porovnány. V případě jazyka Clojure byl benchmark spuštěn přímo příkazem lein run (tedy vlastně v režimu interpretace – resp. přesněji řečeno průběžného překladu do bajtkódu) a následně byl proveden překlad do bajtkódu s uložením do JARu se spuštěním bajtkódu. Obě alternativy vypadají následovně:

$ time lein run
$ lein uberjar
$ time java -jar pi_1-0.1.0-SNAPSHOT-standalone.jar 

Následuje tabulka s výsledky benchmarků:

# Interpret/runtime Varianta real user sys
1 GNU Guile interpret 4,858 5,212 0,058
2 Chicken Scheme interpret 8,137 7,738 0,318
3 Gambit (gsi) interpret 46,689 46,610 0,007
4 Gambit (gsi) interpret (flonum) 8,188 8,169 0,008
5 Gambit (gsc) přeložený 37,454 37,390 0,008
6 Gambit (gsc) přeložený (flonum) 0,153 0,141 0,011
7 Gambit (gsc) přeložený (vlákna) 36,867 36,800 0,013
8 Gambit (gsc) přeložený (vlákna+flonum) 0,159 0,150 0,009
9 Clojure interpret 14,925 16,365 0,515
10 Clojure bajtkód 6,107 7,177 0,394
11 Clojure interpret, vlákna 10,684 18,007 0,634
12 Clojure bajtkód, vlákna 3,691 8,765 0,491

Obrázek 5: Výsledky benchmarků.

bitcoin školení listopad 24

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

Zdrojové kódy všech dnes použitých demonstračních příkladů byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/lisp-families.git (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Příklad Popis příkladu Cesta
1 begin.scm použití programových bloků begin https://github.com/tisnik/lisp-families/blob/master/gambit/begin.scm
2 boolean_ops.scm základní Booleovské operace https://github.com/tisnik/lisp-families/blob/master/gambit/bo­olean_ops.scm
3 closure1.scm uzávěry v jazyce Scheme – počitadlo https://github.com/tisnik/lisp-families/blob/master/gambit/clo­sure1.scm
4 closure2.scm uzávěry v jazyce Scheme – počitadlo https://github.com/tisnik/lisp-families/blob/master/gambit/clo­sure2.scm
5 cond.scm rozhodovací konstrukce cond https://github.com/tisnik/lisp-families/blob/master/gambit/cond.scm
6 cond2.scm další příklad použití rozhodovací konstrukce cond https://github.com/tisnik/lisp-families/blob/master/gambit/cond2.scm
7 cons.scm speciální forma cons https://github.com/tisnik/lisp-families/blob/master/gambit/cons.scm
8 define_type.scm definice nového datového typu https://github.com/tisnik/lisp-families/blob/master/gambit/de­fine_type.scm
9 dot_pairs.scm konstrukce tečka dvojic https://github.com/tisnik/lisp-families/blob/master/gambit/dot_pa­irs.scm
10 factorial1.scm rekurzivní výpočet faktoriálu, první varianta https://github.com/tisnik/lisp-families/blob/master/gambit/fac­torial1.scm
11 factorial2.scm rekurzivní výpočet faktoriálu, druhá varianta https://github.com/tisnik/lisp-families/blob/master/gambit/fac­torial2.scm
12 factorial3.scm tail rekurze při výpočtu faktoriálu https://github.com/tisnik/lisp-families/blob/master/gambit/fac­torial3.scm
13 factorial_error.scm příklad s chybou použitý pro ukázku volání interního debuggeru https://github.com/tisnik/lisp-families/blob/master/gambit/fac­torial_error.scm
14 functions_keyparam.scm funkce s pojmenovanými parametry https://github.com/tisnik/lisp-families/blob/master/gambit/fun­ctions_keyparam.scm
15 functions_optional_rest.scm funkce s nepovinnými parametry https://github.com/tisnik/lisp-families/blob/master/gambit/fun­ctions_optional_rest.scm
16 functions_optional.scm funkce s nepovinnými parametry https://github.com/tisnik/lisp-families/blob/master/gambit/fun­ctions_optional.scm
17 functions.scm deklarace a volání funkcí https://github.com/tisnik/lisp-families/blob/master/gambit/fun­ctions.scm
18 functions_varargs.scm funkce s proměnným počtem parametrů https://github.com/tisnik/lisp-families/blob/master/gambit/fun­ctions_varargs.scm
19 lambdas.scm anonymní funkce v jazyku Scheme https://github.com/tisnik/lisp-families/blob/master/gambit/lam­bdas.scm
20 lexical_scope1.scm lexikální oblast platnosti proměnných, příklad 1 https://github.com/tisnik/lisp-families/blob/master/gambit/le­xical_scope1.scm
21 lexical_scope2.scm lexikální oblast platnosti proměnných, příklad 2 https://github.com/tisnik/lisp-families/blob/master/gambit/le­xical_scope2.scm
22 lexical_scope3.scm lexikální oblast platnosti proměnných, příklad 3 https://github.com/tisnik/lisp-families/blob/master/gambit/le­xical_scope3.scm
23 lexical_scope4.scm lexikální oblast platnosti proměnných, příklad 4 https://github.com/tisnik/lisp-families/blob/master/gambit/le­xical_scope4.scm
24 lists.scm operace se seznamy https://github.com/tisnik/lisp-families/blob/master/gambit/lists.scm
25 pi1.scm výpočet konstanty π imperativním způsobem https://github.com/tisnik/lisp-families/blob/master/gambit/pi1.scm
26 pi1_B.scm výpočet konstanty π funkcionálně-imperativním způsobem https://github.com/tisnik/lisp-families/blob/master/gambit/pi1_B­.scm
27 pi1_C.scm výpočet konstanty π funkcionálním způsobem https://github.com/tisnik/lisp-families/blob/master/gambit/pi1_C­.scm
28 pi2.scm optimalizace výpočtu https://github.com/tisnik/lisp-families/blob/master/gambit/pi2.scm
29 pi3_flonum.scm použití datového typu flonum při výpočtu https://github.com/tisnik/lisp-families/blob/master/gambit/pi3_flo­num.scm
30 pi_for_parallel.scm příprava pro paralelní výpočet konstanty π https://github.com/tisnik/lisp-families/blob/master/gambit/pi_for_pa­rallel.scm
31 pi_parallel.scm paralelní výpočet konstanty π https://github.com/tisnik/lisp-families/blob/master/gambit/pi_pa­rallel.scm
32 pi_parallel_flonum.scm paralelní výpočet konstanty π s typem float https://github.com/tisnik/lisp-families/blob/master/gambit/pi_pa­rallel_flonum.scm
33 predicates.scm predikáty Scheme https://github.com/tisnik/lisp-families/blob/master/gambit/pre­dicates.scm
34 vectors1.scm zpracování vektorů https://github.com/tisnik/lisp-families/blob/master/gambit/vec­tors1.scm
35 vectors2.scm zpracování vektorů https://github.com/tisnik/lisp-families/blob/master/gambit/vec­tors2.scm
36 quasiquote.scm quote a quasiquote https://github.com/tisnik/lisp-families/blob/master/gambit/qu­asiquote.scm
37 exceptions.scm výjimky https://github.com/tisnik/lisp-families/blob/master/gambit/ex­ceptions.scm

19. Literatura

  1. Brian Harvey
    „Simply Scheme: Introducing Computer Science“
    1999 MIT
    Dostupné online na adrese https://people.eecs.berke­ley.edu/~bh/ss-toc2.html
  2. Paul R. Wilson
    „An Introduction to Scheme and its Implementation“
    1997
    Dostupné online na adrese https://www.cs.utexas.edu/ftp/gar­bage/cs345/schintro-v14/schintro_toc.html
  3. Dorai Sitaram
    „Teach Yourself Scheme in Fixnum Days“
    1998–2015
    Dostupné online na adrese https://ds26gte.github.io/tyscheme/
  4. Peter Seibel
    „Practical Common Lisp“
    2009
  5. Paul Graham
    „ANSI Common Lisp“
    1995
  6. Gerald Gazdar
    „Natural Language Processing in Lisp: An Introduction to Computational Linguistics“
    1989
  7. Peter Norvig
    „Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp“
    1991
  8. Alex Mileler et.al.
    „Clojure Applied: From Practice to Practitioner“
    2015
  9. „Living Clojure: An Introduction and Training Plan for Developers“
    2015
  10. Dmitri Sotnikov
    „Web Development with Clojure: Build Bulletproof Web Apps with Less Code“
    2016
  11. McCarthy
    „Recursive functions of symbolic expressions and their computation by machine, part I“
    1960
  12. R. Kent Dybvig
    „The Scheme Programming Language“
    2009
  13. Max Hailperin, Barbara Kaiser, Karl Knight
    „Concrete Abstractions“
    1998
  14. Guy L. Steele
    „History of Scheme“
    2006, Sun Microsystems Laboratories
  15. Kolář J., Muller K.:
    „Speciální programovací jazyky“
    Praha 1981
  16. „AutoLISP Release 9, Programmer's reference“
    Autodesk Ltd., October 1987
  17. „AutoLISP Release 10, Programmer's reference“
    Autodesk Ltd., September 1988
  18. 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
  19. Carl Hewitt; Peter Bishop and Richard Steiger
    „A Universal Modular Actor Formalism for Artificial Intelligence“
    1973
  20. Feiman, J.
    „The Gartner Programming Language Survey (October 2001)“
    Gartner Advisory
  21. 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)
  22. Paul Graham
    On Lisp
    Prentice Hall, 1993
    Dostupné online na adrese http://www.paulgraham.com/on­lisptext.html
  23. David S. Touretzky
    Common LISP: A Gentle Introduction to Symbolic Computation (Dover Books on Engineering)
  24. Peter Norvig
    Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp
  25. Patrick Winston, Berthold Horn
    Lisp (3rd Edition)
    ISBN-13: 978–0201083194, ISBN-10: 0201083191
  26. Matthias Felleisen, David Van Horn, Dr. Conrad Barski
    Realm of Racket: Learn to Program, One Game at a Time!
    ISBN-13: 978–1593274917, ISBN-10: 1593274912

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

V této kapitole jsou uvedeny odkazy na všechny předchozí části seriálu o světě programovacích jazyků LISP a Scheme:

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

21. Odkazy na Internetu

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

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.