Programovací jazyk Janet: varianta Clojure vestavitelná do nativních aplikací

20. 2. 2024
Doba čtení: 38 minut

Sdílet

 Autor: Janet lang
Už jsme se setkali s jazyky odvozenými od Clojure či Common LISPU. Ovšem prozatím jsme si nepopsali relativně nový jazyk Janet, jenž je naprogramovaný v céčku a který lze použít jako interpret vložený do aplikací.

Obsah

1. Programovací jazyk Janet: varianta Clojure vestavitelná do nativních aplikací

2. Základní vlastnosti programovacího jazyka Janet

3. Překlad interpretru jazyka Janet

4. Interaktivní smyčka (REPL)

5. Pravidla pro vyhodnocování výrazů

6. Klíčová slova

7. Symboly

8. Neměnitelné kolekce

9. Speciální forma def

10. Anonymní funkce

11. Pojmenované funkce

12. Lokální symboly ve funkcích

13. Uzávěry

14. Rekurze a její limity

15. Imperativní přístup – použití programových smyček

16. Makro loop

17. Další použití makra loop

18. Předchozí části seriálu o LISPovských programovacích jazycích

19. Literatura

20. Odkazy na Internetu

1. Programovací jazyk Janet: varianta Clojure vestavitelná do nativních aplikací

V seriálu o rozsáhlém a současně i dosti nepřehledném světě LISPovských programovacích jazyků jsme se již několikrát setkali s jazyky odvozenými od známého programovacího jazyka Clojure nebo od Common LISPu (popř. od obou těchto jazyků). Ovšem prozatím jsme si nepopsali jazyk nazvaný Janet (což je relativně nový přírůstek). Tento jazyk je z větší části naprogramován v céčku (zatímco Clojure je naprogramován v Javě, alternativně v C#) a díky tomu jsou jeho systémové nároky poměrně malé. Dosti podstatným způsobem se zrychlila také doba inicializace interpretru, což je oblast, v níž je Clojure velmi špatný (a vznikly proto i projekty, které se snaží tento problém řešit, tedy vlastně klasické „narovnáváky na ohýbák“). A to hlavní na závěr – programovací jazyk Janet je snadno vestavitelný do nativních aplikací.

Obrázek 1: Logo programovacího jazyka Clojure.

Z tohoto pohledu se tedy jedná o programovací jazyk ze stejné kategorie, kam zařazujeme GNU Guile či programovací jazyk Lua. V navazujících kapitolách se seznámíme s některými vlastnosti programovacího jazyka Janet.

Obrázek 2: Logo programovacího jazyka Janet.

Poznámka: podobně jako v Clojure jsou i v jazyku Janet podporována makra, s nimiž se taktéž ve stručnosti seznámíme.

2. Základní vlastnosti programovacího jazyka Janet

Programovací jazyk Janet jsme sice v úvodní části dnešního článku zařadili mezi skupinu jazyků inspirovaných jazykem Clojure, to se ovšem týká především syntaxe a sémantiky vlastního jazyka (tedy jak způsobu zápisu výrazů, tak i významu tohoto zápisu). Pokud se ovšem blíže podíváme na způsob práce s hodnotami (values), uvidíme, že se v tomto ohledu jazyk Janet spíše podobá běžným (možná lépe řečeno mainstreamovým) programovacím jazykům. V Clojure jsou totiž hodnoty neměnitelné a navíc se rozlišují tři zcela různě se chovající možnosti změny hodnoty přiřazené k symbolu (včetně podpory transakční paměti) – v tomto programovacím jazyku totiž nenalezneme běžné proměnné. V jazyku Janet je tomu poněkud jinak, protože zde existuje koncept klasických proměnných a rozlišení měnitelné/neměnitelné (muttable/immutable) je dáno datovým typem a nejedná se tedy o vlastnost programovacího jazyka.

Poznámka: ve skutečnosti i v Clojure můžeme pracovat s měnitelnými hodnotami, pokud například použijeme pole či kolekce naprogramované v Javě. Ovšem programátoři používající Clojure se spíše těmto objektům vyhýbají a snaží se o plně funkcionální přístup.

Důležitou součástí prakticky jakéhokoli moderního jazyka jsou datové struktury, které je možné přímo začít používat, a to bez nutnosti jejich ruční implementace. V programovacím jazyku Janet nalezneme celkem šest základních datových struktur rozdělených podle jejich vlastností (tři různá rozhraní, měnitelné vs. neměnitelné). Tyto datové struktury jsou vypsány v následující tabulce:

Typ Měnitelná varianta Neměnitelná varianta
Indexed Array Tuple
Dictionary Table Struct
Bytes Buffer String, Symbol, Keyword

Se způsoby práce s těmito strukturami se seznámíme v praktické části.

A pochopitelně je Janet funkcionálním jazykem v tom smyslu, že funkce jsou plnohodnotnými datovými typy. A pochopitelně jsou podporovány i anonymní funkce, funkce vyššího řádu a uzávěry (closure). K těmto konceptům se ještě vrátíme v dalším textu.

3. Překlad interpretru jazyka Janet

I když je Janet primárně určený (určená?) pro vestavění do dalších aplikací, je možné si nechat přeložit plnohodnotný interpret tohoto jazyka a v něm si vyzkoušet všechny demonstrační příklady, které si v dalším textu ukážeme. Zdrojové kódy Janet jsou dostupné na GitHubu, konkrétně v repositáři na adrese https://github.com/janet-lang/janet. Nejprve si tedy tento repositář naklonujeme:

$ git clone git@github.com:janet-lang/janet.git

Dále provedeme vlastní překlad. K tomuto účelu je nutné mít nainstalován překladač jazyka C (používám GCC), standardní knihovnu céčka, knihovnu pro POSIXové thready a dále pochopitelně linker a taktéž nástroj make. Žádné další závislosti nejsou striktně vyžadovány.

Překlad se spustí takto:

$ make

Samotný překlad interpretru programovacího jazyka Janet je přitom poměrně rychlý a na mém poněkud obstarožním testovacím stroji byl dokončen za jedenáct sekund (včetně spuštění linkeru atd):

real    0m11,425s
user    0m10,884s
sys     0m0,532s

Výsledný interpret je dostupný v podadresáři build:

$ build/janet

V tomto podadresáři jsou umístěny i další soubory vytvořené při překladu, zejména knihovna, kterou lze slinkovat s dalšími aplikacemi. Velikosti těchto souborů jsou poněkud větší, než je tomu například u jazyka Lua, jenž je v tomto ohledu pojat minimalisticky:

-rwxrwxr-x 1 ptisnovs ptisnovs 2,3M Feb 12 14:36 janet
-rwxrwxr-x 1 ptisnovs ptisnovs 1,5M Feb 12 14:36 janet_boot
-rw-rw-r-- 1 ptisnovs ptisnovs 4,6M Feb 12 14:36 libjanet.a
-rwxrwxr-x 1 ptisnovs ptisnovs 2,3M Feb 12 14:36 libjanet.so

Mimochodem, zkontrolujme pro jistotu, na jakých dalších knihovnách interpret závisí:

$ ldd build/janet
 
        linux-vdso.so.1 (0x00007ffc27e99000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f719ad5d000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f719ad3a000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f719ad34000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f719ab42000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f719af87000)

4. Interaktivní smyčka (REPL)

Interaktivní smyčku REPL (Read-Eval-Print Loop) spustíme příkazem build/janet. Na prvním řádku by se měla vypsat verze programovacího jazyka a ihned na řádku druhém takzvaná výzva (prompt). Každá výzva je očíslována, jak ostatně uvidíme dále:

Janet 1.33.0-local linux/x64/gcc - '(doc)' for help
repl:1:>

Jakýkoli zapsaný výraz (a prakticky vše je v jazyku Janet výrazem) se zvaliduje a vyhodnotí. Výsledek se vypíše na novém řádku (nebo na více řádcích):

repl:1:> (* 6 7)
 
42

Důležité je zobrazení nápovědy. Seznam všech aktuálně viditelných symbolů se zobrazí po zavolání makra doc bez parametrů:

repl:6:> (doc)
Poznámka: makra se zapisují jako funkce, ale vyhodnocují se odlišně.

Seznam symbolů je příliš dlouhý, uvedu zde tedy jen zkrácený seznam:

    Bindings:
 
    % %= * *= *args* *current-file* *debug* *defdyn-prefix* *doc-color*
    *doc-width* *err* *err-color* *executable* *exit* *exit-value*
    *ffi-context* *lint-error* *lint-levels* *lint-warn* *macro-form*
    *macro-lints* *out* *peg-grammar* *pretty-format* *profilepath*
    *redef* *syspath* *task-id* + ++ += - -- -= -> ->> -?> -?>> / /= <
    <= = > >= _ abstract? accumulate accumulate2 all all-bindings
    all-dynamics and any? apply array array/clear array/concat
    array/ensure array/fill array/insert array/new array/new-filled
    array/peek array/pop array/push array/remove array/slice array/trim
    array/weak array? as-> as-macro as?-> asm assert bad-compile
    bad-parse band blshift bnot boolean? bor brshift brushift buffer
    buffer/bit buffer/bit-clear buffer/bit-set buffer/bit-toggle
    ...
    ...
    ...

Nápovědu pro konkrétní symbol lze zobrazit opět zavoláním makra doc, tentokrát ovšem s uvedením symbolu, jehož nápovědu potřebujeme znát:

repl:11:> (doc tuple)
 
 
    cfunction
    src/core/corelib.c on line 397, column 1
 
    (tuple & items)
 
    Creates a new tuple that contains items. Returns the new tuple.

Nápověda existuje i pro funkce s „divnými“ jmény:

repl:12:> (doc +)
 
 
    function
 
    (+ & xs)
 
    Returns the sum of all xs. xs must be integers or real numbers
    only. If xs is empty, return 0.

A konečně pro opuštění interaktivní smyčky REPL slouží funkce quit:

repl:1:> (quit)
nil

5. Pravidla pro vyhodnocování výrazů

V této kapitole si ve stručnosti popíšeme způsob zápisu programů a vyhodnocování jednotlivých výrazů. Základem interpretace každého programu zapsaného v jazyku Janet je načtení a rozpoznání jednoho výrazu (read), vyhodnocení tohoto výrazu (eval) a následný tisk výsledné hodnoty výrazu na standardní výstup (print). Pravidla pro vyhodnocení výrazů (někdy se též můžeme setkat s termínem „vyhodnocení forem“) jsou v tomto jazyku, stejně jako v ostatních LISPovských jazycích, ve skutečnosti velmi jednoduchá a přímočará, na rozdíl od mnoha jiných programovacích jazyků (vlastně na rozdíl od všech mainstreamových jazyků). Tato pravidla lze ve zjednodušené podobě sepsat do pouhých několika bodů:

  1. čísla, hodnoty true a false, hodnota nil, řetězce a klíčová slova (keywords) jsou literály, které jsou vyhodnoceny samy na sebe (což je logické – jedná se o dále nedělitelné objekty, tedy o atomy)
  2. hodnotou symbolu je objekt, který je na tento symbol navázán (analogie z jiných programovacích jazyků – hodnotou proměnné zapsané svým jménem je hodnota uložená do proměnné)
  3. seznamy jsou vyhodnocovány tak, že se první prvek seznamu chápe jako jméno funkce (či jako jméno takzvané speciální formy), které je předán zbytek seznamu jako parametry této funkce (nebo speciální formy)
  4. v případě, že seznam obsahuje podseznamy, jsou tyto podseznamy vyhodnoceny nejdříve, přičemž úroveň rekurzivního zanořování při vyhodnocování podseznamů není teoreticky omezena (tj. podseznamy lze vnořovat do téměř libovolné úrovně)
  5. makra jsou expandována a výsledek této expanze je rekurzivně vyhodnocen
  6. ostatní hodnoty (pole apod.) jsou vyhodnoceny samy na sebe, což například znamená, že pole vrátí svoji hodnotu atd.
Poznámka: většina hodnot tedy při vyhodnocování vrátí samu sebe. Jedinými výjimkami a vlastně i jedinými netriviálními stavebními prvky jazyka Janet jsou seznamy a makra.

Příklady vyhodnocení různých výrazů přímo v REPLu jazyka Janet:

repl:1:> "Hello, world!"
"Hello, world!"
 
repl:2:> :toto-je-keyword
:toto-je-keyword
 
repl:3:> 'toto-je-symbol
toto-je-symbol
 
repl:4:> true
true
 
repl:5:> false
false
 
repl:6:> nil
nil
 
repl:7:> (+ 1 2)
3
 
repl:8:> [1 2 3 4]
(1 2 3 4)
 
repl:9:> @[1 2 3 4]
@[1 2 3 4]
 
repl:10:> (1 2 3 4)
repl:10:1: compile error: 1 expects 1 argument, got 3
Poznámka: posledním výrazem je seznam, ovšem jeho prvním prvkem není volatelná funkce. Z tohoto důvodu je nahlášena chyba při pokusu o vyhodnocení tohoto výrazu.

6. Klíčová slova

Dalším typem literálu podporovaného programovacím jazykem Janet jsou takzvané symboly známé už z LISPu, ke kterým se v jazyce Janet 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 jazyce Janet 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. Na co se tedy vlastně v praxi tento typ formy hodí? Jedním z důvodů zavedení tohoto typu formy do programovacího jazyka Janet byla podpora pro datového typu (kolekce) struct (tedy mapy), v níž 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:

repl:1:> :foo
:foo
 
repl:2:> :toto-je-taktez-keyword
:toto-je-taktez-keyword
 
repl:3:> :i.toto.je.keyword
:i.toto.je.keyword

Ve skutečnosti je dvojtečka uváděná před klíčovým heslem jen syntaktickým cukrem, protože „plný“ zápis (v tomto případě speciální) formy představující klíčové heslo vypadá takto:

repl:5:> (keyword 'foo)
:foo
 
repl:6:> (keyword 'toto-je-taktez-keyword)
:toto-je-taktez-keyword

Klíčová slova lze porovnávat. Stejně napsané klíčové slovo je vždy totožné s jiným stejně napsaným slovem (to ovšem nemusí platit u všech datových typů):

repl:7:> (= :foo :bar)
false
 
repl:8:> (= :foo :foo)
true

7. Symboly

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 je smyčka REPL vyhodnotí:

repl:1:> 'symbol
symbol
 
repl:2:> 'i-toto-je-symbol
i-toto-je-symbol
 
repl:3:> 'toto.je.taktez.symbol
toto.je.taktez.symbol
Poznámka: povšimněte si, že po vyhodnocení v REPL „zmizí“ apostrof původně uvedený před jménem symbolu.

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:

repl:4:> (quote symbol)
symbol
 
repl:5:> (quote i-toto-je-symbol)
i-toto-je-symbol
 
repl:8:> (quote toto.je.taktez.symbol)
toto.je.taktez.symbol

To, že se v obou případech jedná skutečně o stejný symbol, lze zjistit s využitím funkce ekvivalence:

repl:9:> (= 'toto-je-symbol (quote toto-je-symbol))
true

8. Neměnitelné kolekce

Velmi důležitá je podpora pro práci s kolekcemi. Mezi ty patří n-tice (vektory) a struktury. N-tice se v jazyce Clojure nazývá vektor a má poněkud odlišné vlastnosti (má totiž odlišnou interní strukturu, která například umožňuje sdílení struktury). Datový typ struktura zhruba – svými základními vlastnostmi – odpovídá mapě (slovníku) v Clojure, ovšem opět platí, že interně jsou tyto hodnoty reprezentovány odlišným způsobem. Povšimněte si taktéž, že v jazyce Janet je za n-tici považován i typ seznam. Z tohoto pohledu je tedy Janet LISPovským jazykem, ovšem bez seznamů (LIS v názvu LISP značí list):

# Typ kolekce Zápis (syntaktický cukr) Konstruktor
1 n-tice (vektor) [prvky] či '(prvky) (tuple prvky)
2 struktura {dvojice klíč-hodnota} (struct)
Poznámka: n-tici lze zapsat jak stylem [prvky], tak i '(prvky). Ve druhém případě se nesmí zapomenout na apostrof, jinak by byl první prvek v n-tici interpretován jako název funkce. Aby se oba zápisy odlišily, nazývá se první zápis bracketed tuple. Interně se oba typy n-tice sice odlišují, ovšem ve většině příkladů rozdíl nepoznáme – bude se lišit jen „pretty printing“ a zjištění typu.

Zápis n-tice:

repl:1:> '(1 2 3 4)
(1 2 3 4)
 
repl:2:> [1 2 3 4]
(1 2 3 4)
 
repl:3:> [1 [2 3] 4]
(1 (2 3) 4)
 
repl:4:> [1 [2 [3 [4 5 6]]]]
(1 (2 (3 (4 5 6))))
 
repl:5:> (tuple 1 2 3 4)
(1 2 3 4)

Zápis struktury:

repl:1:> {"name" "Pavel" "surname" "Tisnovsky"}
{"name" "Pavel" "surname" "Tisnovsky"}
 
repl:2:>  {:name "Pavel" :surname "Tisnovsky"}
{:name "Pavel" :surname "Tisnovsky"}
 
repl:3:> (struct :name "Pavel" :surname "Tisnovsky")
{:name "Pavel" :surname "Tisnovsky"}
Poznámka: v posledních dvou výrazech jsme jako klíče použili klíčová slova. To je idiomatický přístup využívaný jak v jazyku Clojure, tak i v jazyku Janet.

Kombinace struktury a n-tice:

repl:10:> {:name "Pavel" :grades [:A :C :F :F :B]}
{:grades (:A :C :F :F :B) :name "Pavel"}

Opačná kombinace n-tice a struktury:

repl:11:> [{:name "Pavel" :id 42} {:name "Petr" :id nil}]
({:id 42 :name "Pavel"} {:name "Petr"})
Poznámka: povšimněte si, že hodnota nil (tedy vlastně None) navázaná na klíč není vypsána.

9. Speciální forma def

Důležitá je i speciální forma nazvaná def:

repl:7:> (doc def)
 
 
    special form
 
    (def ...)
 
    See https://janet-lang.org/docs/specials.html

Tato speciální forma se většinou používá k navázání libovolné hodnoty (například čísla, pravdivostní hodnoty, řetězce, struktury a jak uvidíme dále, tak i funkce) na nějaký symbol. Méně časté je použití této speciální formy k pouhému vytvoření symbolu. V případě, že interpret jazyka Janet vyhodnotí („spustí“) tuto speciální formu, dojde k vytvoření nové globální proměnné v aktuálně nastaveném jmenném prostoru. Pokud již globální proměnná stejného jména existuje, dojde k „přepisu“ její hodnoty. Ve skutečnosti však stará hodnota nemusí přestat existovat, protože může být navázána na další proměnné:

repl:1:> (def x true)
true
 
repl:2:> (def y "foo")
"foo"
 
repl:3:> (def z :keyword)
:keyword
 
repl:4:> (def w (+ 1 2))
3
 
repl:5:> (def x false)
false
Poznámka: v posledním případě se nejedná o změnu hodnoty proměnné, ale o vytvoření nové vazby symbol+hodnota. Modifikace hodnoty proměnné se provádí odlišným způsobem.

K symbolům lze přiřadit i metadata:

repl:10:> (def a :answer 42)
42

Metadat může být i větší množství:

repl:11:> (def a :answer :todo :need-tests 42)
42

Přiřadit lze i hodnoty k více symbolům. Například takto:

repl:12:> (def [a b c] [10 20 30])
(10 20 30)
 
repl:13:> a
10
 
repl:14:> b
20
 
repl:15:> c
30

10. Anonymní funkce

Pro vytvoření nové bezejmenné (tj. anonymní) funkce se v jazyku Janet (ale i v Clojure) používá speciální forma nazvaná fn:

repl:8:> (doc fn)
 
 
    special form
 
    (fn ...)
 
    See https://janet-lang.org/docs/specials.html

Této speciální formě se v tom nejjednodušším případě předá vektor obsahující jména parametrů, za nímž je uveden seznam, který představuje tělo funkce (znalci LISPu patrně znají formu lambda, která má podobný význam. Samozřejmě, že v těle funkce je možné použít symbolická jména jejích parametrů a návratovou hodnotou funkce je hodnota získaná vyhodnocením těla funkce. Speciální forma fn při použití ve smyčce REPL vypíše řetězec, který reprezentuje interní identifikátor funkce – jinými slovy na tento řetězec můžeme v naprosté většině případů zapomenout, protože se s ním přímo nepracuje. Ukažme si tedy způsob deklarace funkce se dvěma parametry pojmenovanými x a y, která vypočítá a vrátí součet těchto parametrů:

; anonymní funkce
(fn [x y] (+ x y))
<function 0x556614507790>

Co se vlastně stalo? Vytvořili jsme novou funkci, která však nebyla přiřazena k žádnému symbolu (tj. nebyla „pojmenována“) ani jsme tuto funkci nikde nezavolali. Výše uvedený zápis je tedy prakticky stejně užitečný, jako prosté zapsání jakékoli hodnoty nebo symbolu na vstup smyčky REPL. Pokud by se funkce měla zavolat, lze použít nám již známý zápis ve tvaru seznamu – již víme, že prvním parametrem vyhodnocovaného seznamu (není před ním apostrof!) je funkce a dalšími prvky pak parametry této funkce:

((fn [x y] (* x y)) 6 7)
42

Sice je pěkné, že jsme dokázali funkci zavolat s předáním parametrů, ovšem mnohdy (ne vždy!) je nutné funkci „pojmenovat“, přesněji řečeno ji přiřadit k symbolu. My vlastně již víme, jak se to dělá, protože funkce jsou hodnotami a pro přiřazení symbolu k hodnotě se používá speciální forma setv. Tudíž následující zápis je sice zdlouhavý, ale zcela korektní:

repl:4:> (def add (fn [x y] (+ x y)))
<function 0x556614509A10>

Předchozím příkazem jsme vytvořili novou funkci a navázali ji na symbol, tudíž došlo k jejímu pojmenování. Nyní je již možné funkci zavolat s využitím navázaného symbolu. Samozřejmě se zde opět využívá nám již známý zápis ve tvaru seznamu:

repl:5:> (add 10 20)
30

11. Pojmenované funkce

Vzhledem k tomu, že se uživatelské funkce v reálných programech vytváří a současně i pojmenovávají velmi často, vznikla potřeba nahradit zápis (def název (fn parametry (tělo))) něčím kratším, ideálně i s použitím menšího množství závorek. Pro tyto účely vzniklo makro se jménem defn, které se až na malé detaily podobá LISPovskému zápisu defun:

repl:9:> (doc defn)
 
 
    macro
    boot.janet on line 10, column 1
 
    (defn name & more)
 
    Define a function. Equivalent to (def name (fn name [args] ...)).
Poznámka: v tomto případě se může jednat o makro postavené na speciálních formách def a fn. Ovšem obě zmíněná jména již musí být realizována jako speciální forma.

Při použití makra defn se v tom nejjednodušším případě předávají tři parametry: název nově vytvářené funkce, vektor obsahující jména parametrů funkce a konečně seznam představující tělo této funkce. Naši funkci multiply tedy můžeme vytvořit a současně i pojmenovat následujícím způsobem:

repl:10:> (defn multiply [x y] (* x y))

A ihned ji můžeme použít:

repl:11:> (multiply 6 7)
42

12. Lokální symboly ve funkcích

Ve funkcích se často používají lokální symboly, resp. lokální proměnné s mezivýsledky výpočtů atd. Ty lze vytvářet makrem let. Prvním parametrem tohoto makra je n-tice obsahující dvojice jméno_symbolu výraz. Do symbolu bude dosazen vypočtený výraz. A dalšími parametry makra je programový blok s jedním či více výrazy. Výsledek posledního výrazu je současně i výsledkem celého aplikovaného makra:

repl:1:> (doc let)
 
 
    macro
    boot.janet on line 221, column 1
 
    (let bindings & body)
 
    Create a scope and bind values to symbols. Each pair in bindings is
    assigned as if with def, and the body of the let form returns the
    last value.

Příklad s konstantními výrazy:

(defn foo []
    (let [x 1 y 2] (+ x y)))
 
repl:4:> (foo)
3

Ovšem čitelnější zápis funkce foo by mohl vypadat takto:

(defn foo []
    (let [x 1
          y 2]
       (+ x y)))

Následuje praktičtější příklad, který sečte absolutní hodnoty argumentů funkce add-abs:

(defn add-abs
    [x y]
    (let [abs-x (if (< x 0) (- x) x)
          abs-y (if (< y 0) (- y) y)]
        (+ abs-x abs-y)))

Příklady použití:

repl:22:> (add-abs 10 20)
30
 
repl:23:> (add-abs 10 -20)
30
 
repl:24:> (add-abs -10 -20)
30

13. Uzávěry

Podpora lokálních symbolů a hodnot, které může funkce vracet, má ovšem dalekosáhlejší důsledky, které mj. ovlivňují činnost správce paměti atd. Jedná se o to, že pokud je nějaká proměnná (která je definovaná vně funkce) na funkci navázána (prakticky: je ve funkci použita), nemůže hodnota této proměnné jednoduše zaniknout ani při opuštění daného bloku, protože společně s funkcí tvoří takzvaný uzávěr (closure). S uzávěry se v LISPovské rodině jazyků setkáme velmi často a dnes je nalezneme i v některých dalších programovacích jazycích (zdaleka ne ve všech).

Příkladem může být „konstruktor funkcí“ mul_prep, který na základě jediného předaného parametru vytvoří a vrátí funkci, která bude (při svém pozdějším volání) násobit svůj argument tímto parametrem:

(defn mul_prep [x]
    (fn [y] (* x y))) ; toto je návratová hodnota typu funkce

Necháme si tímto konstruktorem vytvořit funkci pro vynásobení jediného argumentu dvojkou:

(def doubler (mul_prep 2))

A použijeme ji:

repl:18:> (doubler 1)
2

Podobně lze vytvořit konstruktor funkcí pro porovnání předané hodnoty s předem nastaveným limitem:

(defn larger-than [limit]
    (fn (value) (> value limit))) ; toto je návratová hodnota typu funkce

Příklad použití:

repl:3:> (def larger-than-5 (larger-than 5))
<function 0x55615507E860>
 
repl:4:> (larger-than-5 10)
true
 
repl:5:> (larger-than-5 2)
false
 
repl:6:> (larger-than-5 4)
false
 
repl:7:> (filter larger-than-5 '(1 2 3 4 5 6 7 8 9 10))
@[6 7 8 9 10]

14. Rekurze a její limity

Ve funkcionálních programovacích jazycích se velmi často setkáme s algoritmy založenými na rekurzi a na tail rekurzi. Zcela typickým příkladem rekurzivní funkce je funkce pro výpočet faktoriálu, jejíž jednoduchá varianta (neochráněná před všemi typy vstupů) může vypadat takto:

; rekurzivní výpočet faktoriálu
 
(defn factorial
    [n]
    (if (<= n 1)
        1
        (* n (factorial (- n 1)))))

Otestování takto definované je snadné:

(factorial 10)
3628800
Poznámka: pro velká n již nedostaneme korektní výsledek (v Clojure by to naproti tomu bylo možné díky podpoře práce s neomezenými hodnotami):
repl:22:> (factorial 1000)
inf

Pro ještě větší hodnoty n ovšem dojde k následující chybě:

repl:25:> (factorial 1000000000)
src/core/fiber.c:122 - janet out of memory

Důvod, proč předchozí volání funkce factorial skončilo s chybou, spočívá v tom, že došlo k přeplnění zásobníku při rekurzivním volání. Na zásobník se totiž musí ukládat parametry předávané volané funkci a taktéž body návratu (zjednodušeně řečeno návratové adresy). Tento problém se řeší buď tail rekurzí (optimalizace jazyka) nebo explicitním zápisem programové smyčky, což sice není příliš funkcionální přístup, ale jedná se o technologii, kterou programovací jazyk Janet nabízí.

15. Imperativní přístup – použití programových smyček

Na rozdíl od programovacího jazyka Clojure je možné v jazyce Janet použít i běžný (mainstreamový) imperativní přístup. Týká se to mj. i podpory programových smyček. Základem je přitom programová smyčka typu while, která je realizována jako speciální forma:

repl:87:> (doc while)
 
 
    special form
 
    (while ...)
 
    See https://janet-lang.org/docs/specials.html

Podívejme se nyní na to, jakým způsobem lze přepsat výpočet faktoriálu z funkcionální podoby založené na přímé rekurzi do imperativní podoby založené na programové smyčce while a proměnných vytvářených speciální formou var. Proměnné deklarované přes var jsou měnitelné (immutable). Povšimněte si též funkce ++, která dokáže zvýšit hodnotu proměnné, podobně jako stejně pojmenovaný operátor známý z jiných programovacích jazyků:

(defn factorial
    [n]
    (var i 1)
    (var result 1)
    (while (<= i n)
        (*= result i)
        (++ i))
    result)

Pro programové smyčky s počitadlem je navíc možné namísto speciální formy while (která je pro tyto účely příliš primitivní) použít makro for, které je do značné míry podobné příkazu for z jazyků odvozených od céčka:

repl:88:> (doc for)
 
 
    macro
    boot.janet on line 503, column 1
 
    (for i start stop & body)
 
    Do a C-style for-loop for side effects. Returns nil.

Přepis výpočtu faktoriálu tak, aby se využilo makro for, může vypadat takto:

(defn factorial
    [n]
    (var result 1)
    (for i 1 (+ n 1)
        (*= result i))
    result)
Poznámka: v případě, že je zapotřebí pouze několikrát opakovat výpočet, ovšem bez použití počitadla, je možné využít i makro repeat:
repl:13:> (doc repeat)
 
 
    macro
    boot.janet on line 518, column 1
 
    (repeat n & body)
 
    Evaluate body n times. If n is negative, body will be evaluated 0
    times. Evaluates to nil.

16. Makro loop

V programovacím jazyku Janet nalezneme i velmi mocné (a interně komplikované) makro nazvané loop, které je do značné míry převzaté z Common LISPu. Toto makro programátorům nabízí svůj vlastní doménově specifický jazyk (DSL). Z dalších demonstračních příkladů bude patrné, že tento jazyk používá styl zápisu, který je kombinací klasických strukturovaných jazyků (Algol, Pascal, C) a možností LISPu. Je tomu tak z toho důvodu, aby bylo přímo ze zápisu smyčky, typicky již po přečtení prvního řádku, patrné, jak bude smyčka prováděna. K tomuto účelu se uvnitř smyčky loop používají symboly for, repeat, in, finally atd., které mají svůj speciální význam, ale pouze uvnitř samotné formy loop. Tím se loop do značné míry liší od smyček v klasických jazycích, které programátory „nutí“ realizovat kód smyčky v jejím těle, což nemusí být vždy idiomatické:

repl:89:> (doc loop)
 
 
    macro
    boot.janet on line 534, column 1
 
    (loop head & body)
 
    A general purpose loop macro. This macro is similar to the Common
    Lisp loop macro, although intentionally much smaller in scope. The
    head of the loop should be a tuple that contains a sequence of
    either bindings or conditionals. A binding is a sequence of three
    values that define something to loop over. Bindings are written in
    the format:

V dnešním článku si ukážeme jen základní způsob použití tohoto makra, a to opět při výpočtu faktoriálu. Předchozí příklady lze transformovat do této podoby:

(defn factorial
    [n]
    (var result 1)
    (loop [i :range [1 (+ n 1)]]
        (*= result i))
    result)

Ještě je vhodné nahradit výraz (+ n 1) za (inc n), což je v LISPovských jazycích idiomatičtější:

(defn factorial
    [n]
    (var result 1)
    (loop [i :range [1 (inc n)]]
        (*= result i))
    result)

Navíc je možné použít smyčku počítající až do horní meze (včetně), což celý zápis opět zkrátí a zpřehlední:

(defn factorial
    [n]
    (var result 1)
    (loop [i :range-to [1 n]]
        (*= result i))
    result)

17. Další použití makra loop

Podívejme se pro úplnost na některé další možnosti použití makra loop. Můžeme například přidat podmínku pro vykonání těla smyčky (tedy v jiných jazycích by se jednalo o kombinaci smyčky for s podmíněným blokem if):

(var total 0)
(loop [i :range [0 10] :when (< i 5)] (+= total i))
(print total)

Tato smyčka by měla vypsat hodnotu 10, protože se sečetla čísla 0 a až 4 (včetně).

Otočení podmínky záměnou slova :when za :unless:

(var total 0)
(loop [i :range [0 10] :unless (< i 5)] (+= total i))
(print total)

Ukončení smyčky při nesplnění podmínky:

(var total 0)
(loop [i :range [0 10] :while (< i 5)] (+= total i))
(print total)

A naopak ukončení smyčky při splnění podmínky:

(var total 0)
(loop [i :range [0 10] :until (< i 5)] (+= total i))
(print total)

Počítání směrem dolů:

repl:5:> (loop [i :down [10 0]] (print i))
10
9
8
7
6
5
4
3
2
1
nil

Taktéž počítání směrem dolů, ovšem nyní včetně dolní mezní hodnoty:

repl:7:> (loop [i :down-to [10 0]] (print i))
10
9
8
7
6
5
4
3
2
1
0

Iterace přes všechny prvky n-tice:

(loop [i :in [1 2 3 4 10]]
   (print i))

Mělo by se vypsat:

1
2
3
4
10

Což je ovšem možné zkrátit využitím makra each:

repl:24:> (doc each)
 
 
    macro
    boot.janet on line 529, column 1
 
    (each x ds & body)
 
    Loop over each value in ds. Returns nil.

Zkrácený zápis bude vypadat následovně:

(each i [1 2 3 4 10] (print i))

Iterace přes prvky (tedy dvojice klíč+hodnota) uložené ve struktuře:

repl:31:> (def x {"A" 1 "B" 2 "C" 3})
{"A" 1 "B" 2 "C" 3}
 
repl:32:> (loop [[key value] :pairs x] (print key "->" value))
C->3
A->1
B->2
nil

Průchod klíči uloženými ve struktuře:

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):

bitcoin_skoleni

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

Články o Elispu:

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

19. Literatura

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é):

  1. Peter Seibel
    „Practical Common Lisp“
    2009
  2. Paul Graham
    „ANSI Common Lisp“
    1995
  3. Gerald Gazdar
    „Natural Language Processing in Lisp: An Introduction to Computational Linguistics“
    1989
  4. Peter Norvig
    „Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp“
    1991
  5. Alex Mileler et.al.
    „Clojure Applied: From Practice to Practitioner“
    2015
  6. „Living Clojure: An Introduction and Training Plan for Developers“
    2015
  7. Dmitri Sotnikov
    „Web Development with Clojure: Build Bulletproof Web Apps with Less Code“
    2016
  8. McCarthy
    „Recursive functions of symbolic expressions and their computation by machine, part I“
    1960
  9. R. Kent Dybvig
    „The Scheme Programming Language“
    2009
  10. Max Hailperin
    „Concrete Abstractions“
    1998
  11. Guy L. Steele
    „History of Scheme“
    2006, Sun Microsystems Laboratories
  12. Kolář J., Muller K.:
    „Speciální programovací jazyky“
    Praha 1981
  13. „AutoLISP Release 9, Programmer's reference“
    Autodesk Ltd., October 1987
  14. „AutoLISP Release 10, Programmer's reference“
    Autodesk Ltd., September 1988
  15. McCarthy, John; Abrahams, Paul W.; Edwards, Daniel J.; Hart, Timothy P.; Levin, Michael I.
    „LISP 1.5 Programmer's Manual“
    MIT Press. ISBN 0 262 130 1 1 4
  16. Carl Hewitt; Peter Bishop and Richard Steiger
    „A Universal Modular Actor Formalism for Artificial Intelligence“
    1973
  17. Feiman, J.
    „The Gartner Programming Language Survey (October 2001)“
    Gartner Advisory
  18. Harold Abelson, Gerald Jay Sussman, Julie Sussman:
    Structure and Interpretation of Computer Programs
    MIT Press. 1985, 1996 (a možná vyšel i další přetisk)
  19. Paul Graham
    On Lisp
    Prentice Hall, 1993
    Dostupné online na adrese http://www.paulgraham.com/on­lisptext.html
  20. David S. Touretzky
    Common LISP: A Gentle Introduction to Symbolic Computation (Dover Books on Engineering)
  21. Peter Norvig
    Paradigms of Artificial Intelligence Programming: Case Studies in Common Lisp
  22. Patrick Winston, Berthold Horn
    Lisp (3rd Edition)
    ISBN-13: 978–0201083194, ISBN-10: 0201083191
  23. Matthias Felleisen, David Van Horn, Dr. Conrad Barski
    Realm of Racket: Learn to Program, One Game at a Time!
    ISBN-13: 978–1593274917, ISBN-10: 1593274912

20. Odkazy na Internetu

  1. Janet Language
    https://janet-lang.org/
  2. Janet na GitHubu
    https://github.com/janet-lang/janet
  3. Janet for Mortals (a real book)
    https://janet.guide/
  4. Bauble studio
    https://bauble.studio/
  5. Janet na Hacker News
    https://news.ycombinator.com/i­tem?id=34843306
  6. Common Lisp
    https://lisp-lang.org/
  7. Why You Should Learn Lisp In 2022?
    https://www.youtube.com/wat­ch?v=GWdf1flcLoM
  8. LOOP Common Lisps Superior For
    https://www.youtube.com/wat­ch?v=i4tmF_1nZng
  9. Lisp VS C benchmarks
    https://programming-language-benchmarks.vercel.app/lisp-vs-c
  10. Common Lisp: An elegant design pattern
    https://www.youtube.com/wat­ch?v=9597LFlvMuE
  11. Common Lisp Macros By Example Tutorial
    https://lisp-journey.gitlab.io/blog/common-lisp-macros-by-example-tutorial/
  12. The Common Lisp Cookbook
    https://lispcookbook.github.io/cl-cookbook/
  13. The Evolution of Lisp
    https://www.csee.umbc.edu/cou­rses/331/resources/papers/E­volution-of-Lisp.pdf
  14. Awesome CL
    https://github.com/CodyRe­ichert/awesome-cl
  15. LISP
    https://taoofmac.com/space/dev/lisp
  16. Repositář projektu femtolisp
    https://github.com/JeffBe­zanson/femtolisp
  17. Femtolisp – lightweight, robust lisp interpreter built on reusable C libraries
    https://www.findbestopensou­rce.com/product/femtolisp
  18. YCombinator: Femtolisp: A lightweight, robust, scheme-like Lisp implementation
    https://news.ycombinator.com/i­tem?id=22094722
  19. Learning Julia by Anshul Joshi, Rahul Lakhanpal: Femtolisp
    https://www.oreilly.com/li­brary/view/learning-julia/9781785883279/2e85442f-d100–4b53-b8f7–7d20d62f0255.xhtml
  20. The role of femtolisp in Julia?
    https://discourse.julialang.org/t/the-role-of-femtolisp-in-julia/1902
  21. LispSyntax.jl: A clojure-like lisp syntax for julia
    https://github.com/swadey/Lis­pSyntax.jl
  22. 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
  23. Interlisp.org: Dedicated to Restoring and Preserving the Interlisp experience
    https://github.com/Interlisp
  24. Warren Teitelman
    https://en.wikipedia.org/wi­ki/Warren_Teitelman
  25. InterLISP/65
    http://www.atarimania.com/utility-atari-400–800-xl-xe-interlisp-65_12477.html
  26. Lisp Editing in the 80s – Interlisp SEdit (Video)
    https://www.youtube.com/wat­ch?v=2qsmF8HHskg
  27. Inter-LISP
    http://www.atarimania.com/utility-atari-400–800-xl-xe-inter-lisp_29354.html
  28. InterLISP 65 Editing (video)
    https://www.youtube.com/wat­ch?v=nY_hcazo86A
  29. Datasoft INTER-LISP/65 (Atari Age, chat)
    https://atariage.com/forum­s/topic/116093-datasoft-inter-lisp65/
  30. Marvin Minsky – The beauty of the Lisp language (44/151)
    https://www.youtube.com/wat­ch?v=YaWVHyIBVeI
  31. History of LISP (Interlisp)
    http://www.softwarepreser­vation.org/projects/LISP/in­dex.html#INTERLISP_
  32. Computer-Assisted Instruction (Bits and Bytes, Episode 7)
    https://www.youtube.com/wat­ch?v=eURtTV_qKw8
  33. 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/
  34. Gambit in the browser
    https://feeley.github.io/gambit-in-the-browser/
  35. A Tour of Scheme in Gambit
    http://dynamo.iro.umontre­al.ca/wiki/images/a/a7/A_Tou­r_of_Scheme_in_Gambit.pdf
  36. Gambit Scheme: Inside Out
    http://www.iro.umontreal.ca/~gam­bit/Gambit-inside-out.pdf
  37. Gambit Internal Documentation
    http://dynamo.iro.umontre­al.ca/wiki/index.php/Inter­nal_Documentation
  38. clojure-scheme: Compiling to Native Code via Scheme
    http://www.iro.umontreal.ca/~gam­bit/Sorenson-Clojure-to-Native-via-Scheme.pdf
  39. Gauche – a Scheme implementation
    http://practical-scheme.net/gauche/
  40. Scheme48
    https://s48.org/
  41. SISC (Second Interpreter of Scheme)
    http://sisc-scheme.org/
  42. The SCM Implementation of Scheme
    https://people.csail.mit.e­du/jaffer/SCM.html
  43. Ypsilon – The ultimate script language system for the video pinball fourth generation
    http://www.littlewingpinba­ll.com/doc/en/ypsilon/index­.html
  44. Chicken Scheme
    https://call-cc.org/
  45. Eggs Unlimited
    http://wiki.call-cc.org/chicken-projects/egg-index-5.html
  46. Chicken Scheme Wiki
    https://wiki.call-cc.org/
  47. CHICKEN for Python programmers
    https://wiki.call-cc.org/chicken-for-python-programmers
  48. Programming for Performance
    http://wiki.call-cc.org/programming-for-performance
  49. Using the compiler
    https://wiki.call-cc.org/man/4/Using%20the%20compiler
  50. CHICKEN Scheme tutorials
    https://wiki.call-cc.org/tutorials
  51. Traditional Turtles
    https://docs.racket-lang.org/turtles/Traditio­nal_Turtles.html
  52. [racket] How best to repeat a function call n times?
    https://lists.racket-lang.org/users/archive/2014-September/064203.html
  53. Racket: Macros
    https://www.it.uu.se/edu/cou­rse/homepage/avfunpro/ht13/lec­tures/Racket-3-Macros.pdf
  54. Beautiful Racket / explainers: Macros
    https://beautifulracket.com/ex­plainer/macros.html
  55. Macros (dokumentace k Racketu)
    https://docs.racket-lang.org/guide/macros.html
  56. Model syntaxe jazyka Racket
    https://docs.racket-lang.org/reference/syntax-model.html
  57. Syntax Objects
    https://docs.racket-lang.org/guide/stx-obj.html
  58. Tech behind Tech: Clojure Macros Simplified
    http://techbehindtech.com/2010/09/28/clo­jure-macros-simplified/
  59. Fatvat – Exploring functional programming: Clojure Macros
    http://www.fatvat.co.uk/2009/02/clo­jure-macros.html
  60. Beautiful Racket: an introduction to language-oriented programming using Racket
    https://beautifulracket.com/
  61. Stránky projektu Racket
    https://racket-lang.org/
  62. Dokumentace k projektu Racket
    https://docs.racket-lang.org/index.html
  63. Seznam dostupných balíčků pro Racket
    https://pkgs.racket-lang.org/
  64. Racket na Wikipedii
    https://en.wikipedia.org/wi­ki/Racket_(programming_lan­guage)
  65. Vector Library (R7RS-compatible)
    https://srfi.schemers.org/srfi-133/srfi-133.html
  66. Blogy o Racketu a navazujících technologiích
    https://blog.racket-lang.org/
  67. Prográmky psané v Racketu na RosettaCode
    http://rosettacode.org/wi­ki/Category:Racket
  68. Fear of Macros
    https://www.greghendershott.com/fear-of-macros/
  69. Rackjure
    https://github.com/greghen­dershott/rackjure
  70. 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/
  71. Racket News
    https://racket-news.com/
  72. Racket: Lisp for learning
    https://lwn.net/Articles/795385/
  73. Future of Racket
    https://www.greghendershot­t.com/2019/07/future-of-racket.html
  74. Vectors (pro Gauche)
    https://practical-scheme.net/gauche/man/gauche-refe/Vectors.html
  75. Kawa: Compiling Scheme to Java
    https://www.mit.edu/afs.new/sip­b/project/kawa/doc/kawa-tour.html
  76. Kawa in Languages shootout
    http://per.bothner.com/blog/2010/Kawa-in-shootout/
  77. Kawa 2.0 Supports Scheme R7RS
    https://developers.slashdot­.org/story/14/12/13/2259225/ka­wa-20-supports-scheme-r7rs/
  78. Kawa — fast scripting on the Java platform
    https://lwn.net/Articles/623349/
  79. Tail call (a její optimalizace)
    https://en.wikipedia.org/wi­ki/Tail_call
  80. SLIME (Wikipedia)
    http://en.wikipedia.org/wiki/SLIME
  81. slime.vim
    http://s3.amazonaws.com/mps/slime.vim
  82. What are the best scheme implementations?
    https://www.slant.co/topic­s/5282/~scheme-implementations
  83. Bigloo homepage
    http://www-sop.inria.fr/mimosa/fp/Bigloo/
  84. FTP s tarbally Bigloo
    ftp://ftp-sop.inria.fr/indes/fp/Bigloo
  85. GOTO 2018 • Functional Programming in 40 Minutes • Russ Olsen
    https://www.youtube.com/wat­ch?v=0if71HOyVjY
  86. TinyScheme (stránka na Sourceforge)
    http://tinyscheme.sourcefor­ge.net/home.html
  87. Embedding Tiny Scheme in a Game
    http://www.silicondelight­.com/embedding-tiny-scheme-in-a-game/
  88. Embedding Scheme for a game mission scripting DSL
    http://carloscarrasco.com/embedding-scheme-for-a-game-mission-scripting-dsl.html
  89. Všechny verze TinyScheme na SourceForge
    https://sourceforge.net/pro­jects/tinyscheme/files/ti­nyscheme/
  90. Fork TinyScheme na GitHubu
    https://github.com/yawnt/tinyscheme
  91. Ackermannova funkce
    https://cs.wikipedia.org/wi­ki/Ackermannova_funkce
  92. Ackermann function na Rosetta Code
    https://rosettacode.org/wi­ki/Ackermann_function#Sche­me
  93. Success Stories (lisp.org)
    https://lisp-lang.org/success/
  94. Allegro Common Lisp Success Stories
    https://franz.com/success/
  95. Clojure Success Stories
    https://clojure.org/commu­nity/success_stories
  96. Scheme Quick Reference
    https://www.st.cs.uni-saarland.de/edu/config-ss04/scheme-quickref.pdf
  97. Slajdy o Scheme (od slajdu číslo 15)
    https://docs.google.com/pre­sentation/d/1abmDnKjrq1tcjGvvRNAK­hOiSTSE2lyagtcEPal07Gbo/e­dit
  98. Scheme Cheat Sheet
    https://github.com/smythp/scheme-cheat-sheet
  99. Embedding Lua, embedding Guile
    http://puntoblogspot.blog­spot.com/2013/04/embedding-lua-embedding-guile.html
  100. Lambda Papers
    https://en.wikisource.org/wi­ki/Lambda_Papers
  101. Revised7Report on the Algorithmic Language Scheme
    https://small.r7rs.org/at­tachment/r7rs.pdf
  102. 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/
  103. Why is Scheme my first language in university?
    https://softwareengineerin­g.stackexchange.com/questi­ons/115252/why-is-scheme-my-first-language-in-university
  104. The Perils of JavaSchools
    https://www.joelonsoftware­.com/2005/12/29/the-perils-of-javaschools-2/
  105. How to Design Programs, Second Edition
    https://htdp.org/2019–02–24/index.html
  106. LilyPond
    http://lilypond.org/
  107. LilyPond — Extending (přes Scheme)
    http://lilypond.org/doc/v2­.18/Documentation/extendin­g/scheme-tutorial
  108. Scheme in LilyPond
    http://lilypond.org/doc/v2­.18/Documentation/extendin­g/scheme-in-lilypond
  109. GnuCash
    http://www.gnucash.org/
  110. Custom Reports (in GNU Cash)
    https://wiki.gnucash.org/wi­ki/Custom_Reports
  111. Program by Design
    https://programbydesign.org/
  112. SchemePy
    https://pypi.org/project/SchemePy/
  113. 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
  114. femtolisp
    https://github.com/JeffBe­zanson/femtolisp
  115. (How to Write a (Lisp) Interpreter (in Python))
    http://norvig.com/lispy.html
  116. Repositář s Guile Emacsem
    http://git.hcoop.net/?p=bpt/guile.git
  117. Interacting with Guile Compound Data Types in C
    http://www.lonelycactus.com/gu­ilebook/x1555.html
  118. Calling Guile functions from C
    http://www.lonelycactus.com/gu­ilebook/c1204.html#SECCAL­LGUILEFUNC
  119. Arrays, and other compound data types
    http://www.lonelycactus.com/gu­ilebook/charrays.html
  120. Interacting with Guile Compound Data Types in C
    http://www.lonelycactus.com/gu­ilebook/x1555.html
  121. Guile Reference Manual
    https://www.gnu.org/softwa­re/guile/manual/html_node/in­dex.html
  122. Scheme: Summary of Common Syntax
    https://www.gnu.org/softwa­re/guile/manual/html_node/Syn­tax-Summary.html#Syntax-Summary
  123. Scripting with Guile: Extension language enhances C and Scheme
    https://www.ibm.com/develo­perworks/library/l-guile/index.html
  124. Having fun with Guile: a tutorial
    http://dustycloud.org/misc/guile-tutorial.html
  125. Guile: Loading Readline Support
    https://www.gnu.org/softwa­re/guile/manual/html_node/Lo­ading-Readline-Support.html#Loading-Readline-Support
  126. lispy
    https://pypi.org/project/lispy/
  127. Lython
    https://pypi.org/project/Lython/
  128. Lizpop
    https://pypi.org/project/lizpop/
  129. Budoucnost programovacích jazyků
    http://www.knesl.com/budoucnost-programovacich-jazyku
  130. LISP Prolog and Evolution
    http://blog.samibadawi.com/2013/05/lisp-prolog-and-evolution.html
  131. List of Lisp-family programming languages
    https://en.wikipedia.org/wi­ki/List_of_Lisp-family_programming_languages
  132. clojure_py na indexu PyPi
    https://pypi.python.org/py­pi/clojure_py
  133. PyClojure
    https://github.com/eigenhom­bre/PyClojure
  134. Hy na GitHubu
    https://github.com/hylang/hy
  135. Hy: The survival guide
    https://notes.pault.ag/hy-survival-guide/
  136. Hy běžící na monitoru terminálu společnosti Symbolics
    http://try-hy.appspot.com/
  137. Welcome to Hy’s documentation!
    http://docs.hylang.org/en/stable/
  138. Hy na PyPi
    https://pypi.org/project/hy/#des­cription
  139. Getting Hy on Python
    https://lwn.net/Articles/596626/
  140. Programming Can Be Fun with Hy
    https://opensourceforu.com/2014/02/pro­gramming-can-fun-hy/
  141. Přednáška o projektu Hy (pětiminutový lighttalk)
    http://blog.pault.ag/day/2013/04/02
  142. Hy (Wikipedia)
    https://en.wikipedia.org/wiki/Hy
  143. GNU Emacs Lisp Reference Manual: Point
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Point.html
  144. GNU Emacs Lisp Reference Manual: Narrowing
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Narrowing.html
  145. GNU Emacs Lisp Reference Manual: Functions that Create Markers
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Creating-Markers.html
  146. GNU Emacs Lisp Reference Manual: Motion
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Motion.html#Motion
  147. GNU Emacs Lisp Reference Manual: Basic Char Syntax
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­lisp/Basic-Char-Syntax.html
  148. Elisp: Sequence: List, Array
    http://ergoemacs.org/emac­s/elisp_list_vs_vector.html
  149. Elisp: Property List
    http://ergoemacs.org/emac­s/elisp_property_list.html
  150. Elisp: Hash Table
    http://ergoemacs.org/emac­s/elisp_hash_table.html
  151. Elisp: Association List
    http://ergoemacs.org/emac­s/elisp_association_list.html
  152. The mapcar Function (An Introduction to Programming in Emacs Lisp)
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­intr/mapcar.html
  153. Anaphoric macro
    https://en.wikipedia.org/wi­ki/Anaphoric_macro
  154. Some Common Lisp Loop Macro Examples
    https://www.youtube.com/wat­ch?v=3yl8o6r_omw
  155. A Guided Tour of Emacs
    https://www.gnu.org/softwa­re/emacs/tour/
  156. The Roots of Lisp
    http://www.paulgraham.com/ro­otsoflisp.html
  157. Evil (Emacs Wiki)
    https://www.emacswiki.org/emacs/Evil
  158. Evil (na GitHubu)
    https://github.com/emacs-evil/evil
  159. Evil (na stránkách repositáře MELPA)
    https://melpa.org/#/evil
  160. 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
  161. GNU Emacs (home page)
    https://www.gnu.org/software/emacs/
  162. GNU Emacs (texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?GnuEmacs
  163. An Introduction To Using GDB Under Emacs
    http://tedlab.mit.edu/~dr/gdbin­tro.html
  164. An Introduction to Programming in Emacs Lisp
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­intr/index.html
  165. 27.6 Running Debuggers Under Emacs
    https://www.gnu.org/softwa­re/emacs/manual/html_node/e­macs/Debuggers.html
  166. GdbMode
    http://www.emacswiki.org/e­macs/GdbMode
  167. Emacs (Wikipedia)
    https://en.wikipedia.org/wiki/Emacs
  168. Emacs timeline
    http://www.jwz.org/doc/emacs-timeline.html
  169. Emacs Text Editors Family
    http://texteditors.org/cgi-bin/wiki.pl?EmacsFamily
  170. Vrapper aneb spojení možností Vimu a Eclipse
    https://mojefedora.cz/vrapper-aneb-spojeni-moznosti-vimu-a-eclipse/
  171. 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/
  172. Emacs/Evil-mode – A basic reference to using evil mode in Emacs
    http://www.aakarshnair.com/posts/emacs-evil-mode-cheatsheet
  173. From Vim to Emacs+Evil chaotic migration guide
    https://juanjoalvarez.net/es/de­tail/2014/sep/19/vim-emacsevil-chaotic-migration-guide/
  174. Introduction to evil-mode {video)
    https://www.youtube.com/wat­ch?v=PeVQwYUxYEg
  175. EINE (Emacs Wiki)
    http://www.emacswiki.org/emacs/EINE
  176. EINE (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?EINE
  177. ZWEI (Emacs Wiki)
    http://www.emacswiki.org/emacs/ZWEI
  178. ZWEI (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?ZWEI
  179. Zmacs (Wikipedia)
    https://en.wikipedia.org/wiki/Zmacs
  180. Zmacs (Texteditors.org)
    http://texteditors.org/cgi-bin/wiki.pl?Zmacs
  181. TecoEmacs (Emacs Wiki)
    http://www.emacswiki.org/e­macs/TecoEmacs
  182. Micro Emacs
    http://www.emacswiki.org/e­macs/MicroEmacs
  183. Micro Emacs (Wikipedia)
    https://en.wikipedia.org/wi­ki/MicroEMACS
  184. EmacsHistory
    http://www.emacswiki.org/e­macs/EmacsHistory
  185. Seznam editorů s ovládáním podobným Emacsu či kompatibilních s příkazy Emacsu
    http://www.finseth.com/emacs.html
  186. evil-numbers
    https://github.com/cofi/evil-numbers
  187. Debuggery a jejich nadstavby v Linuxu (1.část)
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu/
  188. Debuggery a jejich nadstavby v Linuxu (2.část)
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-2-cast/
  189. Debuggery a jejich nadstavby v Linuxu (3): Nemiver
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-3-nemiver/
  190. Debuggery a jejich nadstavby v Linuxu (4): KDbg
    http://fedora.cz/debuggery-a-jejich-nadstavby-v-linuxu-4-kdbg/
  191. 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/
  192. Org mode
    https://orgmode.org/
  193. The Org Manual
    https://orgmode.org/manual/index.html
  194. Kakoune (modální textový editor)
    http://kakoune.org/
  195. Vim-style keybinding in Emacs/Evil-mode
    https://gist.github.com/tro­yp/6b4c9e1c8670200c04c16036805773d8
  196. Emacs – jak začít
    http://www.abclinuxu.cz/clan­ky/navody/emacs-jak-zacit
  197. Programovací jazyk LISP a LISP machines
    https://www.root.cz/clanky/pro­gramovaci-jazyk-lisp-a-lisp-machines/
  198. Evil-surround
    https://github.com/emacs-evil/evil-surround
  199. Spacemacs
    http://spacemacs.org/
  200. Lisp: Common Lisp, Racket, Clojure, Emacs Lisp
    http://hyperpolyglot.org/lisp
  201. Common Lisp, Scheme, Clojure, And Elisp Compared
    http://irreal.org/blog/?p=725
  202. Does Elisp Suck?
    http://irreal.org/blog/?p=675
  203. Emacs pro mírně pokročilé (9): Elisp
    https://www.root.cz/clanky/emacs-elisp/
  204. 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/
  205. Clojure(Script) Interactive Development Environment that Rocks!
    https://github.com/clojure-emacs/cider
  206. An Introduction to Emacs Lisp
    https://harryrschwartz.com/2014/04/08/an-introduction-to-emacs-lisp.html
  207. Emergency Elisp
    http://steve-yegge.blogspot.com/2008/01/emergency-elisp.html
  208. Lambda calculus
    https://en.wikipedia.org/wi­ki/Lambda_calculus
  209. 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/
  210. Micro Manual LISP
    https://www.scribd.com/do­cument/54050141/Micro-Manual-LISP

Autor článku

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