Hlavní navigace

Calysto Hy: integrace programovacího jazyka Hy s Jupyter Notebookem

23. 3. 2021
Doba čtení: 43 minut

Sdílet

 Autor: Pavel Tišnovský
V dnešním článku si ukážeme způsob integrace programovacího jazyka Hy, což je homoikonický jazyk odvozený od Lispu/Clojure a běžící ve virtuálním stroji Pythonu, s Jupyter Notebookem. Integraci zajišťuje kernel Calysto Hy.

Obsah

1. Calysto Hy: integrace programovacího jazyka Hy s Jupyter Notebookem

2. Programovací jazyk Hy

3. Instalace Jupyter Notebooku

4. Instalace projektu Calysto Hy

5. Registrace nového kernelu do Jupyter Notebooku a spuštění Jupyter Notebooku

6. Základní datové typy jazyka Hy

7. Zpracování kolekcí – vektorů a slovníků – v jazyku Hy

8. Funkce a makra určená pro práci se slovníky

9. Volání funkcí a metod definovaných v Pythonu

10. Jazyk Hy a knihovna Numpy

11. Volání funkcí definovaných v jazyku Hy z Pythonu

12. Makrosystém programovacího jazyka Hy

13. Využití eval, homoikonicita jazyků

14. Makra „quote“ a „syntax-quote“

15. Praktické použití – jednoduchá makra vytvořená v jazyku Hy

16. Spuštění samotného interpretru jazyka Hy a práce s interaktivní smyčkou REPL

17. Dodatek: Dostupné kernely pro Jupyter Notebook

18. Předchozí články o Jupyter Notebooku

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

20. Odkazy na Internetu

1. Calysto Hy: integrace programovacího jazyka Hy s Jupyter Notebookem

V dnešním článku si ukážeme, jakým způsobem je možné zajistit integraci programovacího jazyka Hy (což je homoikonický jazyk odvozený od Lispu a běžící ve virtuálním stroji Pythonu) s Jupyter Notebookem. Jedná se tedy o pokračování článků, v nichž jsme si představili propojení Jupyter Notebooku s programovacím jazykem R, Go a v neposlední řadě taktéž s jazykem Clojure.

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

Čtenář si zajisté může položit otázku, proč by vlastně měl jazyk Hy vyzkoušet a jaké nové či lepší vlastnosti mu přinese. Pravděpodobně největším přínosem je – podobně jako v dalších lispovských jazycích – homoikonocita umožňující metaprogramování. Dalším přínosem je snadnější manipulace se symboly. Nesmíme ale zapomenout ani na další vlastnosti jazyka Hy, například na možnost práce se zlomky (fraction) namísto výpočtů s numerickými hodnotami reprezentovanými podle IEEE 754 (v Pythonu konkrétně s double, v knihovně NumPy pak i s dalšími typy, a to včetně typu half). Výpočty se zlomky jsou sice pomalejší, neboť pro normalizaci výsledků se používá softwarové řešení a nikoli možnosti poskytované matematickým koprocesorem, ovšem mnoho nepříjemných vlastností typů s plovoucí řádovou čárkou se zde neobjevuje (například je možné přesně pracovat s desetinnými hodnotami atd.). Určitou nevýhodu představuje fakt, že nelze reprezentovat například 1/0 (tedy nekonečno) nebo 0/0.

Obrázek 2: Logo projektu Jupyter Notebook.

Poznámka: pro Jupyter Notebook existují ještě minimálně dva další reálně použitelné projekty, které uživatelům-programátorům umožňují pracovat s LISPovským programovacím jazykem. Jeden z těchto projektů se jmenuje Calysto Scheme a lze ho najít na adrese https://github.com/Calysto/ca­lysto_scheme (podobnost s Calysto Hy není náhodná). Druhý z těchto projektů integruje s Jupyter Notebookem programovací jazyk Clojure a setkali jsme se s ním v článku s titulkem Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku. Mezi těmito projekty existují značné rozdíly. Calysto Scheme je klasickou implementací programovacího jazyka Scheme, takže jsou podporovány například continuations. V případě Clojupyteru se jedná o plnohodnotný jazyk Clojure, se všemi výhodami i zápory, které to přináší (start JVM atd.). a Calysto Hy je z tohoto pohledu „lehkotonážní“ jazyk postavený nad možnostmi virtuálního stroje Pythonu.

Obrázek 3: Logo známé knihovny NumPy.

2. Programovací jazyk Hy

Programovací jazyk Hy je ve velké míře inspirován (poměrně populárním) jazykem Clojure, s nímž jsme se na stránkách Roota již mnohokrát setkali v samostatném seriálu. Ovšem zatímco interpret programovacího jazyka Clojure překládá všechny zapsané výrazy (resp. přesněji řečeno formy) do bajtkódu JVM a teprve poté je spouští, pracuje jazyk Hy odlišně, protože kód generuje s využitím AST a dokonce dokáže zdrojový LISPovský kód transformovat do Pythonu a teprve poté ho spustit (takže se vlastně jedná o transpiler). To je výhodná vlastnost, protože umožňuje Hy poměrně snadno integrovat například s debuggery atd. Překlad přes AST nebo Python podporuje jak Python 2.x, tak i Python 3.x. Další důležitou vlastností Hy je možnost plné kooperace mezi kódem zapsaným přímo v tomto jazyku a Pythoním kódem, což znamená, že je možné použít všechny pythonovské knihovny a frameworky (včetně Numpy, PyTorch, Flask atd.) a naopak – například mít napsanou aplikaci v Pythonu a pro manipulaci se symboly použít Hy (v tomto ohledu jsou homoikonické programovací jazyky s podporou maker a ideálně i neměnitelných datových struktur podle mého názoru mnohem lepší, než samotný Python).

A právě možnost použít jazyk Hy společně s naprostou většinou balíčků programovacího jazyka Python umožnila integraci jazyka Hy do projektu Jupyter Notebook.

Fakt, že různé dialekty jazyků LISP a Scheme vznikají pro prakticky všechny moderní virtuální stroje (typicky pro JVM, VM JavaScriptu nebo VM Pythonu) vlastně není nic překvapivého. Musíme si totiž uvědomit, že praktická použitelnost programovacího jazyka je do značné míry určena i celým ekosystémem, který je programátorům k dispozici. A ekosystém Pythonu je dnes již velmi rozsáhlý a obsahuje kvalitní a v celém světě používané knihovny i celé frameworky, takže se může jednat o vhodný základ, na němž je možné postavit moderní varianty LISPu či Scheme. Podobným způsobem ostatně vznikl i programovací jazyk Clojure (což je taktéž dialekt LISPu, i když v mnoha ohledech vylepšený a navíc od běžných Lispů odlišný), který vlastně vůbec nemá svůj vlastní virtuální stroj – původně Clojure vzniklo pro virtuální stroj Javy (JVM), další varianty posléze byly implementovány pro CLR (ClojureCLR) a ClojureScript, který je kompilovaný do JavaScriptu, takže může běžet buď v prohlížeči, v Node.js atd.

Pro virtuální stroj Pythonu je v současnosti k dispozici hned několik dialektů LISPu, Scheme či Clojure. Jedná se například o méně známé projekty Lizpop, Lispy či Lython, dále o SchemePy (ten mimochodem tvoří základ pro integraci Scheme s Jupyter Notebookem – o tom však až jindy), Clojure-py o němž se zmíníme v dalším textu a především velmi zajímavým způsobem implementovaný programovací jazyk Hy, kterému je věnována větší část dnešního článku. Do této kategorie částečně spadá i jazyk Pixie, s nímž jsme se již na stránkách Roota ve stručnosti seznámili.

3. Instalace Jupyter Notebooku

S programovacím jazykem Hy se pochopitelně seznámíme prakticky a využijeme přitom interaktivní prostředí Jupyter Notebooku. To je možné nainstalovat hned několika způsoby, podle toho, zda se využijí balíčky dostupné přímo v repositáři dané linuxové distribuce nebo se použijí jiní správci balíčků (typicky conda nebo pip). Prakticky všechny oficiálně podporované postupy instalace jsou zmíněny v diagramu umístěném na stránce https://jupyter.readthedoc­s.io/en/latest/projects/con­tent-projects.html.

Ve Fedoře (27 a výše) lze instalaci provést příkazem:

$ sudo dnf install python3-notebook

Instalace na Linux Mintu a dalších distribucích odvozených od Ubuntu nebo Debianu:

$ sudo apt-get install python3-notebook

Samozřejmě se nainstaluje i velká řada podpůrných balíčků:

Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  fonts-font-awesome fonts-glyphicons-halflings javascript-common jupyter-core jupyter-nbextension-jupyter-js-widgets jupyter-notebook libjs-backbone libjs-bootstrap
  libjs-bootstrap-tour libjs-codemirror libjs-es6-promise libjs-jed libjs-jquery libjs-jquery-typeahead libjs-jquery-ui libjs-marked libjs-moment libjs-requirejs
  libjs-requirejs-text libjs-text-encoding libjs-underscore libjs-xterm pandoc pandoc-data python3-attr python3-bleach python3-dateutil python3-defusedxml
  python3-html5lib python3-importlib-metadata python3-ipykernel python3-ipywidgets python3-jinja2 python3-jsonschema python3-jupyter-client python3-jupyter-core
  python3-mistune python3-more-itertools python3-nbconvert python3-nbformat python3-pandocfilters python3-prometheus-client python3-pyrsistent python3-send2trash
  python3-terminado python3-testpath python3-tornado python3-webencodings python3-widgetsnbextension python3-zipp python3-zmq
Suggested packages:
  apache2 | lighttpd | httpd libjs-jquery-lazyload libjs-json libjs-jquery-ui-docs texlive-latex-recommended texlive-xetex texlive-luatex pandoc-citeproc
  texlive-latex-extra context wkhtmltopdf librsvg2-bin groff ghc nodejs php python ruby r-base-core node-katex python-attr-doc python-bleach-doc python3-genshi
  python3-lxml python-ipywidgets-doc python-jinja2-doc python-jsonschema-doc python-nbconvert-doc python-notebook-doc python-tornado-doc python3-twisted
The following NEW packages will be installed:
  fonts-font-awesome fonts-glyphicons-halflings javascript-common jupyter-core jupyter-nbextension-jupyter-js-widgets jupyter-notebook libjs-backbone libjs-bootstrap
  libjs-bootstrap-tour libjs-codemirror libjs-es6-promise libjs-jed libjs-jquery libjs-jquery-typeahead libjs-jquery-ui libjs-marked libjs-moment libjs-requirejs
  libjs-requirejs-text libjs-text-encoding libjs-underscore libjs-xterm pandoc pandoc-data python3-attr python3-bleach python3-dateutil python3-defusedxml
  python3-html5lib python3-importlib-metadata python3-ipykernel python3-ipywidgets python3-jinja2 python3-jsonschema python3-jupyter-client python3-jupyter-core
  python3-mistune python3-more-itertools python3-nbconvert python3-nbformat python3-notebook python3-pandocfilters python3-prometheus-client python3-pyrsistent
  python3-send2trash python3-terminado python3-testpath python3-tornado python3-webencodings python3-widgetsnbextension python3-zipp python3-zmq
0 upgraded, 52 newly installed, 0 to remove and 424 not upgraded.
Need to get 21,1 MB of archives.
After this operation, 165 MB of additional disk space will be used.
Do you want to continue? [Y/n]

Využít je možné i výše zmíněného správce balíčků Conda. V případě, že tento nástroj používáte, bude instalace vypadat následovně:

$ conda install -c conda-forge notebook

A konečně lze použít i klasický pip nebo pip3 (v závislosti na tom, jaký je stav Pythonu 3 na daném operačním systému):

$ pip install notebook

V případě, že pip instaluje balíčky pro Python 2 a nikoli pro Python 3, použijeme:

$ pip3 install notebook

Použít je možné i spuštění v kontejneru. Konkrétně pro Docker je k dispozici hned několik obrazů Jupyter Notebooku, každý s rozdílnými kernely a dalšími moduly. Viz https://hub.docker.com/u/jupyter/#!.

4. Instalace projektu Calysto Hy

Po instalaci Jupyter Notebooku provedeného v rámci předchozí kapitoly nainstalujeme projekt Calysto Hy, který zajišťuje integraci jazyka Hy právě s Jupyter Notebookem. Pro zajímavost provedeme instalaci v rámci virtuálního prostředí Pythonu zajištěného známým nástrojem Virtualenv. Pochopitelně lze provést i instalaci pro celý operační systém, popř. pro aktuálně přihlášeného uživatele, ale pro testování a rozšiřování Jupyter Notebooku může být použití virtuálního prostředí bezpečnější (jednoduchým přepínáním mezi virtuálními prostředími lze omezit či změnit počet dostupných kernelů atd.).

Nejprve vytvoříme adresář, který bude obsahovat nástroje a balíčky nainstalované v rámci virtuálního prostředí:

$ python3 -m venv calysto_hy

Dále virtuální prostředí aktivujeme:

$ source calysto_hy/bin/activate

To by se mělo projevit úpravou výzvy (prompt):

(calysto_hy) bash-4.4$

Dalším krokem je instalace balíčku Jedhy, jenž zajišťuje automatické doplňování kódu, prohlížení dokumentace atd. pro jazyk Hy:

(calysto_hy) bash-4.4$ pip3 install git+https://github.com/ekaschalk/jedhy.git
 
Collecting git+https://github.com/ekaschalk/jedhy.git
  Cloning https://github.com/ekaschalk/jedhy.git to /tmp/ramdisk/pip-27q_yyiv-build
Collecting toolz (from jedhy==1)
  Downloading https://files.pythonhosted.org/packages/12/f5/537e55f8ba664ff2a26f26913010fb0fcb98b6bbadc6158af888184fd0b7/toolz-0.11.1-py3-none-any.whl (55kB)
Installing collected packages: toolz, jedhy
  Running setup.py install for jedhy: started
    Running setup.py install for jedhy: finished with status 'done'
Successfully installed jedhy-1 toolz-0.11.1
You are using pip version 9.0.3, however version 21.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

Podobně nainstalujeme samotný balíček Calysto Hy:

(calysto_hy) bash-4.4$ pip3 install git+https://github.com/Calysto/calysto_hy.git
 
Collecting git+https://github.com/Calysto/calysto_hy.git
  Cloning https://github.com/Calysto/calysto_hy.git to /tmp/ramdisk/pip-rvdrr46p-build
Collecting metakernel (from calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/a4/3f/b4db994950bb1443228f097be3c0827f106641a18f0243f37bc1bd747a0a/metakernel-0.27.5-py2.py3-none-any.whl (208kB)
Collecting hy (from calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/42/5b/2a6930c12112b1e773e1c97d9c6cad9bf4b448d31daab53654b7ff2481cc/hy-0.20.0-py2.py3-none-any.whl (83kB)
Requirement already satisfied: toolz in ./calysto_hy/lib/python3.6/site-packages (from calysto-hy==0.1.1)
Collecting ipykernel (from metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/56/95/3a670c8b2c2370bd8631c313f42e60983b3113ffec4035940592252bd6d5/ipykernel-5.5.0-py3-none-any.whl (120kB)
Collecting pexpect>=4.2 (from metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/39/7b/88dbb785881c28a102619d46423cb853b46dbccc70d3ac362d99773a78ce/pexpect-4.8.0-py2.py3-none-any.whl (59kB)
Collecting astor>=0.8 (from hy->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/c3/88/97eef84f48fa04fbd6750e62dcceafba6c63c81b7ac1420856c8dcc0a3f9/astor-0.8.1-py2.py3-none-any.whl
Collecting rply>=0.7.7 (from hy->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/c0/7c/f66be9e75485ae6901ae77d8bdbc3c0e99ca748ab927b3e18205759bde09/rply-0.7.8-py2.py3-none-any.whl
Collecting funcparserlib>=0.3.6 (from hy->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/cb/f7/b4a59c3ccf67c0082546eaeb454da1a6610e924d2e7a2a21f337ecae7b40/funcparserlib-0.3.6.tar.gz
Collecting colorama (from hy->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/44/98/5b86278fbbf250d239ae0ecb724f8572af1c91f4a11edf4d36a206189440/colorama-0.4.4-py2.py3-none-any.whl
Collecting ipython>=5.0.0 (from ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/23/6a/210816c943c9aeeb29e4e18a298f14bf0e118fe222a23e13bfcc2d41b0a4/ipython-7.16.1-py3-none-any.whl (785kB)
Collecting traitlets>=4.1.0 (from ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/ca/ab/872a23e29cec3cf2594af7e857f18b687ad21039c1f9b922fac5b9b142d5/traitlets-4.3.3-py2.py3-none-any.whl (75kB)
Collecting jupyter-client (from ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/77/e8/c3cf72a32a697256608d5fa96360c431adec6e1c6709ba7f13f99ff5ee04/jupyter_client-6.1.12-py3-none-any.whl (112kB)
Collecting tornado>=4.2 (from ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/01/d1/8750ad20cbcefb499bb8b405e243f83c2c89f78d139e6f8c8d800640f554/tornado-6.1-cp36-cp36m-manylinux1_x86_64.whl (427kB)
Collecting ptyprocess>=0.5 (from pexpect>=4.2->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl
Collecting appdirs (from rply>=0.7.7->hy->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl
Collecting backcall (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/4c/1c/ff6546b6c12603d8dd1070aa3c3d273ad4c07f5771689a7b69a550e8c951/backcall-0.2.0-py2.py3-none-any.whl
Collecting prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/ce/ee/08ceeb759c570bf96b4c636582ebf18c14c3c844a601b2e77b17f462aa6b/prompt_toolkit-3.0.17-py3-none-any.whl (367kB)
Requirement already satisfied: setuptools>=18.5 in ./calysto_hy/lib/python3.6/site-packages (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
Collecting decorator (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/ed/1b/72a1821152d07cf1d8b6fce298aeb06a7eb90f4d6d41acec9861e7cc6df0/decorator-4.4.2-py2.py3-none-any.whl
Collecting pygments (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/3a/80/a52c0a7c5939737c6dca75a831e89658ecb6f590fb7752ac777d221937b9/Pygments-2.8.1-py3-none-any.whl (983kB)
Collecting pickleshare (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/9a/41/220f49aaea88bc6fa6cba8d05ecf24676326156c23b991e80b3f2fc24c77/pickleshare-0.7.5-py2.py3-none-any.whl
Collecting jedi>=0.10 (from ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/f9/36/7aa67ae2663025b49e8426ead0bad983fee1b73f472536e9790655da0277/jedi-0.18.0-py2.py3-none-any.whl (1.4MB)
Collecting six (from traitlets>=4.1.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Collecting ipython-genutils (from traitlets>=4.1.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/fa/bc/9bd3b5c2b4774d5f33b2d544f1460be9df7df2fe42f352135381c347c69a/ipython_genutils-0.2.0-py2.py3-none-any.whl
Collecting jupyter-core>=4.6.0 (from jupyter-client->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/53/40/5af36bffa0af3ac71d3a6fc6709de10e4f6ff7c01745b8bc4715372189c9/jupyter_core-4.7.1-py3-none-any.whl (82kB)
Collecting pyzmq>=13 (from jupyter-client->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/7c/8f/e83fc0060a7626d3555b971a70a37a0d57f727ec7ec860e9aadf96fdd724/pyzmq-22.0.3-cp36-cp36m-manylinux1_x86_64.whl (1.1MB)
Collecting python-dateutil>=2.1 (from jupyter-client->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/d4/70/d60450c3dd48ef87586924207ae8907090de0b306af2bce5d134d78615cb/python_dateutil-2.8.1-py2.py3-none-any.whl (227kB)
Collecting wcwidth (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/59/7c/e39aca596badaf1b78e8f547c807b04dae603a433d3e7a7e04d67f2ef3e5/wcwidth-0.2.5-py2.py3-none-any.whl
Collecting parso<0.9.0,>=0.8.0 (from jedi>=0.10->ipython>=5.0.0->ipykernel->metakernel->calysto-hy==0.1.1)
  Downloading https://files.pythonhosted.org/packages/ad/f0/ef6bdb1eba2dbfda60c985cd8d7b47b6ed8c6a1f5d212f39ff50b64f172c/parso-0.8.1-py2.py3-none-any.whl (93kB)
Installing collected packages: backcall, six, decorator, ipython-genutils, traitlets, wcwidth, prompt-toolkit, ptyprocess, pexpect, pygments, pickleshare, parso, jedi, ipython, jupyter-core, pyzmq, python-dateutil, tornado, jupyter-client, ipykernel, metakernel, astor, appdirs, rply, funcparserlib, colorama, hy, calysto-hy
  Running setup.py install for funcparserlib: started
    Running setup.py install for funcparserlib: finished with status 'done'
  Running setup.py install for calysto-hy: started
    Running setup.py install for calysto-hy: finished with status 'done'
Successfully installed appdirs-1.4.4 astor-0.8.1 backcall-0.2.0 calysto-hy-0.1.1 colorama-0.4.4 decorator-4.4.2 funcparserlib-0.3.6 hy-0.20.0 ipykernel-5.5.0 ipython-7.16.1 ipython-genutils-0.2.0 jedi-0.18.0 jupyter-client-6.1.12 jupyter-core-4.7.1 metakernel-0.27.5 parso-0.8.1 pexpect-4.8.0 pickleshare-0.7.5 prompt-toolkit-3.0.17 ptyprocess-0.7.0 pygments-2.8.1 python-dateutil-2.8.1 pyzmq-22.0.3 rply-0.7.8 six-1.15.0 tornado-6.1 traitlets-4.3.3 wcwidth-0.2.5
You are using pip version 9.0.3, however version 21.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.

A konečně v posledním kroku instalace spustíme příkaz pro instalaci Calysto Hy do Notebooku:

python3 -m calysto_hy install --sys-prefix
 
[InstallKernelSpec] Installed kernelspec calysto_hy in /home/ptisnovs/calysto_hy/share/jupyter/kernels/calysto_hy

5. Registrace nového kernelu do Jupyter Notebooku a spuštění Jupyter Notebooku

Pro jistotu se ještě přesvědčíme, že se nový kernel Calysto Hy skutečně zaregistroval do Jupyter Notebooku. Soubor s konfigurací kernelu je uložen v podadresáři calysto_hy/share/jupyter/ker­nels/calysto_hy a měl by vypadat následovně:

{"argv": ["/home/ptisnovs/calysto_hy/bin/python3", "-m", "calysto_hy", "-f", "{connection_file}"], "codemirror_mode": "hy", "display_name": "Calysto Hy", "language": "hy", "name": "calysto_hy"}

Po přeformátování:

{
  "argv": [
    "/home/ptisnovs/calysto_hy/bin/python3",
    "-m",
    "calysto_hy",
    "-f",
    "{connection_file}"
  ],
  "codemirror_mode": "hy",
  "display_name": "Calysto Hy",
  "language": "hy",
  "name": "calysto_hy"
}
Poznámka: v případě, že nový kernel nebude po spuštění Jupyter Notebooku dostupný (viz též další kapitolu), vytvořte symbolický link z adresáře /home/ptisnovs/.local/sha­re/jupyter/kernels na výše uvedený adresář calysto_hy/share/jupyter/ker­nels/calysto_hy.

Ještě před prvním spuštěním Jupyter Notebooku je vhodné si nastavit heslo, které se bude zadávat pro přístup do jeho grafického uživatelského rozhraní:

$ jupyter notebook password
 
Enter password:
Verify password:
[NotebookPasswordApp] Wrote hashed password to /home/ptisnovs/.jupyter/jupyter_notebook_config.json

Nyní konečně nastal čas spustit Jupyter Notebook:

$ jupyter notebook
 
[I 11:26:39.019 NotebookApp] Writing notebook server cookie secret to /run/user/1000/jupyter/notebook_cookie_secret
[W 11:26:39.615 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 11:26:39.629 NotebookApp] Serving notebooks from local directory: /home/ptisnovs
[I 11:26:39.629 NotebookApp] 0 active kernels
[I 11:26:39.629 NotebookApp] The Jupyter Notebook is running at:
[I 11:26:39.629 NotebookApp] http://[all ip addresses on your system]:8888/
[I 11:26:39.629 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[I 11:26:39.983 NotebookApp] 302 GET /tree (::1) 1.91ms

Pokud se zobrazí i řádky zvýrazněné kurzivou, znamená to, že server Jupyter Notebooku bude přístupný z ostatních počítačů v síti. Toto chování (někdy ho vyžadujeme) lze zakázat editací souboru ~/.jupyter/jupyter_notebo­ok_config.json, konkrétně úpravou řádku s klíčem „ip“:

{
  "NotebookApp": {
    "password": "sha1:neco-tay-je",
    "ip": "localhost"
  }
}

Nové spuštění Jupyter Notebooku by již mělo být bezproblémové:

$ jupyter notebook
 
[I 12:28:08.540 NotebookApp] Serving notebooks from local directory: /home/ptisnovs
[I 12:28:08.540 NotebookApp] 0 active kernels
[I 12:28:08.540 NotebookApp] The Jupyter Notebook is running at:
[I 12:28:08.540 NotebookApp] http://localhost:8888/
[I 12:28:08.540 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).

Obrázek 4: První spuštění Jupyter Notebooku.

Obrázek 5: Nabídka vytvoření nového diáře používajícího kernel Calysto Hy.

Obrázek 6: Nový diář založený na kernelu Calysto Hy.

Obrázek 7: Kernel je možné prakticky kdykoli přepnout (i když to zde nedává význam).

6. Základní datové typy jazyka Hy

V této kapitole si popíšeme základní jednoduché datové typy programovacího jazyka Hy. Především se jedná o pravdivostní hodnoty. A právě v tomto ohledu se Hy odlišuje od většiny dalších dialektů LISPu, protože pro pravdivostní hodnoty používá True a False převzaté přímo z Pythonu. I prázdná hodnota se zapisuje jinak, než v mnoha dalších interpretrech LISPu, protože se používá Pythonovské None. Rozdíly mezi různými dialekty LISPu shrnuje následující tabulka:

Dialekt Pravda Nepravda Prázdná hodnota
Common Lisp t nil nil
Scheme #t #f '()
Clojure true false nil
Hy True False None
Poznámka: další zajímavé porovnání různých dialektů LISPu naleznete na stránce http://hyperpolyglot.org/lisp.

Můžeme si to vyzkoušet:

Obrázek 8: Základní datové typy programovacího jazyka Hy.

Programovací jazyk Hy rozlišuje mezi celými čísly, čísly s plovoucí řádovou čárkou, komplexními čísly a konečně zlomky. První tři numerické typy jsou převzaty z Pythonu a jsou s ním plně kompatibilní; zlomky jsou typické pro prakticky všechny LISPovské jazyky a jsou interně implementovány objektem. U numerických hodnot je možné používat prefixy 0×, 0o a 0b:

Obrázek 9: Práce s numerickými hodnotami.

Řetězce se zapisují prakticky stejně jako v Pythonu, ovšem musí se použít uvozovky a nikoli apostrofy (ty mají odlišný význam). Podporovány jsou i prefixy pro Unicode řetězce (výchozí) a tzv. „raw“ řetězce (typicky používané při zápisu regulárních výrazů):

Obrázek 10: Práce s řetězci.

Specialitou jsou tzv.„here dokumenty“, tj. víceřádkové řetězce s prakticky libovolným obsahem, jejichž zápis byl inspirován programovacím jazykem Lua. Tyto řetězce začínají znaky #[XXX[ a končí znaky ]XXX], přičemž za XXX je možné doplnit libovolně dlouhou (i prázdnou) sekvenci znaků, která se v řetězci v ideálním případě nebude vyskytovat:

Obrázek 11: „Here dokumenty“ v jazyku Hy.

7. Zpracování kolekcí – vektorů a slovníků – v jazyku Hy

Ve druhé části dnešního článku se zaměříme na problematiku práce s kolekcemi (tj. zejména s vektory a se slovníky), protože to je jedna z oblastí, v níž se programovací jazyk Hy odlišuje od Clojure (s nímž má jinak velmi mnoho společných vlastností). Důvody pro všechny dále zmíněné rozdíly jsou ve skutečnosti velmi pragmatické – vzhledem k tomu, že v Hy jsou vektory představované Pythonovskými seznamy, není například možné zachovat neměnnost (immutability), což je jeden z hlavních konceptů, na nichž je postaven programovací jazyk Clojure. Většina základních funkcí navíc vrací přímo vektor a nikoli tzv. línou sekvenci (lazy sequence) tak, jak je tomu v Clojure.

Na začátek si uveďme důležitý fakt, že Hy rozlišuje mezi seznamem (list), což je datová struktura podobná klasickému LISPovskému seznamu tvořenému tečka-dvojicemi a mezi vektorem (vector), který odpovídá Pythonovskému seznamu, jehož obsah i tvar (shape) je měnitelný. Vektor se vytvoří následovně:

=> ; vektory nejsou neměnné (immutable) tak jako v Clojure!
=> (setv vektor [1 2 3 4])

Takto vytvořený vektor je možné modifikovat – měnit hodnotu jeho prvků, měnit jeho tvar (shape), tj. počet prvků atd.

V dalších demonstračním příkladech si ukážeme základní funkce určené pro práci s vektory. Jedná se v první řadě o funkci get určenou pro přečtení jednoho prvku ze seznamu na zadaném indexu (indexuje se od nuly) a taktéž o funkce nazvané příznačně first a last pro přístup k prvnímu, resp. k poslednímu prvku. Povšimněte si, že funkce get akceptuje i záporné indexy pro přístup k prvkům od konce vektoru, což vlastně není překvapivé, protože se tato funkce překládá na Pythonovské vektor[index]:

=> ; výraz pro přečtení prvku vektoru
=> (get vektor 1)
2
=> (get vektor -1)
4
=> (get vektor -2)
3
 
=> ; speciální funkce pro významné prvky vektoru
=> (first vektor)
1
=> (last vektor)
4

Další funkce určená pro práci s vektory se jmenuje rest a její chování již více odpovídá chování jazyka Clojure, protože tato funkce nevrací seznam ani vektor, ale iterátor, což je možné považovat za obdobu líné sekvence. Pro převod iterátoru na vektor se používá funkce list, což je sice matoucí, ale musíme si uvědomit, že snahou je zachování co největší úrovně kompatibility s Pythonem:

=> ; převod na sekvenci bez prvního prvku
=> (rest vektor)
<itertools.islice object at 0x7f1237a16f98>
 
=> ; zpětný převod sekvence na vektor
=> (list (rest vektor))
[2, 3, 4]
 
=> ; vylepšený způsob zápisu předchozího výrazu
=> (-> vektor rest list)
[2, 3, 4]

Následuje ukázka použití vektoru vektorů neboli matic, ať již pravidelných nebo nepravidelných:

=> ; dvourozměrný vektor (matice)
=> (setv matice [[1 2 3] [4 5 6] [7 8 9]])
 
=> matice
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
 
=> ; nepravidelná matice
=> (setv matice2 [[1] [2 3] [4 5 6] [7 8 9 10]])
 
=> matice2
[[1], [2, 3], [4, 5, 6], [7, 8, 9, 10]]

Při snaze o vytvoření „plochého“ vektoru použijeme funkci pojmenovanou flatten:

=> (flatten matice)
[1, 2, 3, 4, 5, 6, 7, 8, 9]

Další užitečná funkce cut slouží pro vytvoření dalšího vektoru z vybraných prvků vektoru prvního. Překlad této funkce odpovídá Pythonovskému vektor[od:do], a to včetně možnosti použití záporných indexů:

=> ; získání subvektoru
=> (cut vektor 1 5)
[2, 3, 4]
=> (cut vektor 1)
[2, 3, 4]
=> (cut vektor -5 -2)
[1, 2]
=> (cut vektor -3 -2)
[2]

Třetím nepovinným parametrem je možné určit krok, ať již kladný či záporný:

=> (setv vektor2 (list (range 20)))
 
=> ; sudé prvky
=> (cut vektor2 2 -1 2)
[2, 4, 6, 8, 10, 12, 14, 16, 18]
= 
=> ; otočení vektoru
=> (cut vektor2 -1 0 -1)
[19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
= 
=> ; otočení se získáním jen lichých prvků
=> (cut vektor2 -1 0 -2)
[19, 17, 15, 13, 11, 9, 7, 5, 3, 1]

Pro změnu hodnoty prvku ve vektoru se používá makro assoc, ovšem musíme si dát pozor na to, aby prvek s daným indexem již ve vektoru existoval:

=> ; změna prvku ve vektoru je možná
=> (assoc vektor 2 42)
= 
=> ; POZOR: vyhodí výjimku!
=> (assoc vektor 10 -1)
Traceback (most recent call last):
  File "/home/tester/.local/lib/python3.6/site-packages/hy/importer.py", line 198, in hy_eval
    eval(ast_compile(_ast, <eval_body>", "exec"), namespace)
  File "<eval_body>", line 1, in <module>
IndexError: list assignment index out of range
Poznámka: povšimněte si, že makro asocc nevrací žádnou hodnotu, resp. přesněji řečeno vrací None (odpovídá nil v LISPu). Je tomu tak z toho důvodu, že dochází k modifikaci původního vektoru.

Při mazání prvků z vektoru použijeme funkci del, typicky společně s funkcí cut:

=> (setv vektor2 ["A" "B" "C" "D" "E" "F"])
 
=> vektor2
['A', 'B', 'C', 'D', 'E', 'F']
 
=> (cut vektor2 2 4)
['C', 'D']
 
=> (del (cut vektor2 2 4))
 
=> vektor2
 
['A', 'B', 'E', 'F']
 
=> (-> (cut vektor2 2 4) del)
 
=> vektor2
['A', 'B']

A konečně pro přidání nového prvku do vektoru můžete použít metodu .append, která se zapisuje dvěma způsoby – funkcionálně nebo objektově:

=> ; přidání prvku do vektoru (na jeho konec)
=> (.append vektor 5)
 
=> ; přidání prvku do vektoru (na jeho konec)
=> (vektor.append 5)

Obrázek 12: Práce s vektory.

8. Funkce a makra určená pro práci se slovníky

Další funkce a makra, která si v dnešním článku popíšeme, se týkají práce se slovníky (dictionary). I v této oblasti vidíme inspiraci programovacím jazykem Clojure (konstruktory slovníků), ovšem současně je patrná poměrně úzká návaznost i na samotný programovací jazyk Python. Nejprve si zopakujme, jak vypadá konstruktor slovníku. Ten je jednoduchý – všechny dvojice klíč+hodnota se uvedou do složených závorek:

=> {"prvni" "first" "druhy" "second" "treti" "third"}
{'prvni': 'first', 'druhy': 'second', 'treti': 'third'}

Pro získání hodnoty uložené pod nějakým klíčem se opět používá funkce get, které se ovšem pochopitelně namísto indexu prvku předává klíč (obecně neceločíselný). V případě, že prvek s daným klíčem není nalezen, dojde k běhové výjimce:

=> (setv d1 {:id 1 :name "Eda" :surname "Wasserfall"})
 
=> (get d1 :name)
'Eda'
=> (get d1 :xyname)
Traceback (most recent call last):
  File "/home/tester/.local/lib/python3.6/site-packages/hy/importer.py", line 201, in hy_eval
    return eval(ast_compile(expr, "<eval>", "eval"), namespace)
  File "<eval>", line 1, in <module>
KeyError: '\ufdd0:xyname'

V případě, že se ve funkci get použije větší množství selektorů (indexů, popř. klíčů), je možné vybírat hodnoty z vnořených datových struktur. Opět si to ukažme na velmi jednoduchém demonstračním příkladu, konkrétně na slovníku, který v jednom prvku obsahuje seznam:

=> (setv d2 {:id 1 :name "Eda" :surname "Wasserfall" :actors ["Genadij Rumlena" "Pavel Vondruška"]})
 
=> (get d2 :actors 1)
'Pavel Vondruška'
 
=> (get d2 :actors 0)
'Genadij Rumlena'

I u slovníků lze použít funkci assoc pro přidání další dvojice klíč+hodnota. Slovník je tedy možné vytvořit postupně:

=> (setv d3 {})
 
=> (assoc d3 :id 10)
 
=> (assoc d3 :name "Eda")
 
=> (assoc d3 :surname "Wasserfall")
 
Poznámka: funkce assoc mění původní slovník, na rozdíl od stejně pojmenované funkce v jazyku Clojure, která vytváří slovník nový.

Funkce assoc dokáže přepsat hodnotu prvku, a to ve chvíli, kdy použijeme stejný klíč, který je již ve slovníku obsažen:

=> (assoc d3 :id 10)

Vymazání dvojice klíč+hodnota zajišťuje funkce del:

=> (del (get d3 :surname))
Poznámka: v jazyce Clojure pro tento účel slouží funkce dissoc, ovšem v případě jazyka Hy se používá funkce s podobným názvem, jaký má klíčové slovo del v Pythonu.

Další možností, jak vytvořit slovník, je použití funkce pojmenované zip (ta zazipuje dvě sekvence), ovšem výsledek je nutné na slovník převést:

=> (dict (zip [:id :name :surname] [1 "Eda" "Wasserfall"]))

Nepatrně složitější příklady založené na funkci zip:

=> (repeat "A" 10)
repeat('A', 10)
 
=> (dict (zip (range 10) (repeat "A" 10)))
{0: 'A', 1: 'A', 2: 'A', 3: 'A', 4: 'A', 5: 'A', 6: 'A', 7: 'A', 8: 'A', 9: 'A'}
 
=> (-> (zip (range 10) (range 10 1 -1)) dict)
{0: 10, 1: 9, 2: 8, 3: 7, 4: 6, 5: 5, 6: 4, 7: 3, 8: 2}

Počet hodnot může přesahovat počet klíčů, ovšem hodnoty, které nelze na klíče namapovat, se budou jednoduše ignorovat:

=> (-> (zip (range 10) (range 50 1 -1)) dict)
{0: 50, 1: 49, 2: 48, 3: 47, 4: 46, 5: 45, 6: 44, 7: 43, 8: 42, 9: 41}

Obrázek 13: Práce se slovníky v Hy spuštěném v Jupyter Notebooku.

9. Volání funkcí a metod definovaných v Pythonu

V této kapitole si ukážeme, jakým způsobem můžeme v jazyku Hy použít funkce a metody definované v Pythonu. Pro tento účel si připravíme malý testovací modul nazvaný test_module.py, který obsahuje jak několik funkcí, tak i třídu s konstruktorem a jednou metodou. Navíc je deklarována jedna konstanta:

THE_ANSWER = 42
 
 
def multiply_two_numbers(x, y):
    return x * y
 
 
class uber_class:
    def __init__(self, x):
        self._x = x
 
    def compute_square(self):
        return self._x * self._x

Použití tříd a metod z modulu datetime je snadné. Povšimněte si, že metody lze volat jak stylem (.metoda objekt parametry), tak i stylem (objekt.metoda parametry):

(import [datetime [date :as d]])
 
(setv date (d 2018 02 28))
(print date)
(print date.year)
(print date.month)
(print date.day)
 
(setv now1 (.today d))
(print now1)
(setv now2 (d.today))
(print now2)

Příklad použití konstanty a funkce z našeho testovacího modulu ukazuje, že lze použít jak původní jména (vytvořená podle konvencí Pythonu), tak i jména odpovídající konvencím programovacího jazyka Hy:

(import [test_module [*]])
 
(print THE_ANSWER)
(print *the-answer*)
(print (multiply_two_numbers 6 7))
(print (multiply-two-numbers 6 7))

Alternativní způsob importu do vlastního jmenného prostoru t:

(import [test_module :as t])
 
(print t.THE_ANSWER)
(print t.*the-answer*)
(print (t.multiply_two_numbers 6 7))
(print (t.multiply-two-numbers 6 7))

Konstrukce objektu a volání jeho metody (opět oběma podporovanými způsoby):

(setv u (uber_class 42))
(print u)
(print (u.compute_square))
(print (.compute_square u))

Obrázek 14: Volání funkcí Pythonu v Hy spuštěném v Jupyter Notebooku.

10. Jazyk Hy a knihovna Numpy

Jupyter Notebook se velmi často používá společně s knihovnou Numpy a Matplotlib, popř. s knihovnou Pandas. Všechny tři zmíněné knihovny jsou určeny pro programovací jazyk Python, takže je zřejmé (viz předchozí kapitolu), že tyto knihovny budou bez problémů volatelné i z programovacího jazyka Hy. Samozřejmě je nejprve nutné provést import těchto knihoven:

=> (import numpy)

popř.:

=> (import [numpy :as np])

Ihned poté je možné si zobrazit nápovědu k naimportované knihovně nebo jen jediné funkci:

=> (help np)
 
Help on package numpy:
 
NAME
    numpy
 
DESCRIPTION
    NumPy
    =====
 
    Provides
      1. An array object of arbitrary homogeneous items
      2. Fast mathematical operations over arrays
      3. Linear Algebra, Fourier Transforms, Random Number Generation

Naimportovanou knihovnu můžeme ihned začít používat:

=> (np.arange 1 10)
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
 
=> (np.linspace 1 10)
array([ 1.        ,  1.18367347,  1.36734694,  1.55102041,  1.73469388,
        1.91836735,  2.10204082,  2.28571429,  2.46938776,  2.65306122,
        2.83673469,  3.02040816,  3.20408163,  3.3877551 ,  3.57142857,
        3.75510204,  3.93877551,  4.12244898,  4.30612245,  4.48979592,
        4.67346939,  4.85714286,  5.04081633,  5.2244898 ,  5.40816327,
        5.59183673,  5.7755102 ,  5.95918367,  6.14285714,  6.32653061,
        6.51020408,  6.69387755,  6.87755102,  7.06122449,  7.24489796,
        7.42857143,  7.6122449 ,  7.79591837,  7.97959184,  8.16326531,
        8.34693878,  8.53061224,  8.71428571,  8.89795918,  9.08163265,
        9.26530612,  9.44897959,  9.63265306,  9.81632653, 10.        ])

atd.

Poznámka: samozřejmě se stále používá typový systém Pythonu:
=> (np.array [1 2 3])
array([1, 2, 3])
 
=> (type (np.arange 1 10))
 
<class 'numpy.ndarray'>

Obrázek 15: Volání funkcí z knihovny Numpy v Hy spuštěném v Jupyter Notebooku.

11. Volání funkcí definovaných v jazyku Hy z Pythonu

Nyní si ukážeme opačný směr spolupráce mezi programovacím jazykem Hy a Pythonem, než tomu bylo v deváté a desáté kapitole. Nejdříve nadefinujeme několik funkcí v jazyku Hy a posléze tyto funkce (resp. jen ty funkce, které mají korektní jméno) zavoláme z Pythonu. Nutné přitom je, aby se použilo následující pojmenování souboru s modulem naprogramovaným v Hy:

jméno_modulu.hy
Poznámka: demonstrační příklady z této kapitole nejsou ukázány v Jupyter Notebooku, neboť vyžadují použití dvou kernelů. To je samozřejmě možné, ale již poněkud komplikované.

Vytvoříme tedy soubor nazvaný interop2.hy, který bude mít následující obsah:

; Běžná funkce zapisovaná ve stylu LISPu
(defn calculate-multiplication
    [x y]
    (* x y))
 
 
; Predikáty
(defn zero?
    [x]
    (= x 0))
 
(defn even?
    [x]
    (zero? (% x 2)))
 
(defn odd?
    [x]
    (not (even? x)))
 
 
; Konverzní funkce
(defn string->bool
    [s]
    (= s "true"))
 
(defn deg->rad
    [angle]
    (* angle (/ 3.1415 180)))
 
 
; Privátní funkce
(defn -hidden
    [x]
    (+ x 1))
 
; Funkce psaná velkými písmeny
(defn *major*
    [x]
    (+ x 1))

Všechny funkce, u nichž se podařilo vytvoření korektního pythonovského jména, lze zavolat přímo z Pythonu, a to stejným způsobem, jako jakékoli jiné funkce. Nesmíme zapomenout na import modulu hy a samozřejmě i testovaného modulu (ten se nijak nepřekládá!):

import hy
from interop2 import *
 
print(calculate_multiplication(6, 7))
 
print(is_zero(0))
print(is_zero(1))
print(is_zero(2))
 
print(is_even(0))
print(is_even(1))
print(is_even(2))
 
print(is_odd(0))
print(is_odd(1))
print(is_odd(2))
 
print(MAJOR(1))
 
import interop2
print(interop2._hidden(1))
Můžeme vidět, že interoperabilita mezi jazyky Hy → Python i Python → Hy je na velmi dobré úrovni a oba programátor může vcelku bez problémů využívat možností obou jazyků v jediném projektu (s tím dodatkem, že situace v Jupyter Notebooku je nepatrně komplikovanější).

12. Makrosystém programovacího jazyka Hy

V navazujících kapitolách se ve stručnosti seznámíme s možnostmi makrosystému nabízeného programovacím jazykem Hy. Před zápisem uživatelských maker si však ukažme takzvaná reader makra, která jsou aplikována již ve chvíli načítání jednotlivých výrazů do interpretru. Samotná reader makra jsou velmi jednoduchá, protože nemají přístup k AST (jsou aplikována příliš brzy):

# Makro Název Význam
1 ; comment umožňuje obejít zápis (comment nějaký text) u komentářů
2 ' quote nahrazuje zápis (quote …)
3 ` syntax-quote provádí plnou kvalifikaci symbolů + zde lze použít makra ~ a ~@
4 ~ unquote zajistí, že se vyhodnotí pouze označená část formy (= provede substituci této části výsledkem)
5 ~@ unquote-splicing podobné předchozími makru, ovšem výsledná sekvence se vloží ve formě samostatných prvků do „obalující“ sekvence
6 # dispatch má různé funkce: donutí reader, aby použil makro z jiné tabulky maker

Makro dispatch (poslední v předchozí tabulce) má ve skutečnosti několik významů v závislosti na tom, jaký znak je uveden ihned po křížku (#):

# Dvojice znaků Způsob použití Význam
1 #{ #{prvky} zápis množiny
2 #_ #_text text je ignorován – alternativní způsob komentáře

V uživatelských makrech (těch plnohodnotných) se velmi často používají reader makra syntax-quote a unquote, s nimiž se blíže seznámíme v dalším textu.

13. Využití funkce eval, homoikonicita jazyků

Jednoduchý interpret LISPu mohl být teoreticky implementován pouze s využitím trojice funkcí read (načtení výrazu/formy ze standardního vstupu), print (tisk výsledku vyhodnocení výrazu/formy na standardní výstup), eval (většinou rekurzivně implementovaná funkce určená pro vyhodnocení načtené formy), které byly doplněny speciální formou či makrem loop (nekonečná smyčka – při striktním pohledu se v tomto případě nemůže jednat o funkci). Ve skutečnosti je však samozřejmě nutné, aby byl prakticky použitelný programovací jazyk doplněn o alespoň minimální množství základních funkcí a speciálních forem. V případě původního LISPu se jednalo o sedm funkcí a dvě speciální formy: atom, car, cdr, cond, cons, eq, quote, lambda a konečně label.

Poznámka: tyto funkce a formy jsou skutečně postačující pro plnohodnotný LISP, přičemž samotná implementace LISPu může vypadat takto:

Obrázek 16: Implementace interpretru LISPu
Autor: Paul Graham.

Původně relativně velmi jednoduše a přitom elegantně implementovaný interpret programovacího jazyka LISP se postupně začal vyvíjet a jednou z nových a přitom mocných technik, které do něj byly přidány, jsou takzvaná makra, která se však v mnoha ohledech liší od maker používaných například v programovacích jazycích C a C++. Zatímco v céčku a C++ jsou makra zpracovávána poměrně „hloupým“ preprocesorem, který dokáže provádět textové substituce, načítat vkládané soubory a vyhodnocovat jednoduché podmínky, mohou makra implementovaná v programovacím jazyce LISP pracovat přímo se zadávanými formami, které makra mohou různým způsobem modifikovat – přitom se zde využívá faktu, že v LISPu a tudíž i v programovacím jazyku Hy jsou programy reprezentovány ve formě (obvykle rekurzivně vnořených) seznamů, a změnou obsahu těchto seznamů lze vlastně přímo manipulovat s takzvaným abstraktním syntaktickým stromem (AST – Abstract Syntax Tree).

Poznámka: odlišný makrosystém, než nabízí C a C++, má například jazyk Julia a taktéž programovací jazyk Rust.

Není bez zajímavosti, že s AST se v LISPu nebo Hy může manipulovat za použití stejných mechanismů (funkcí/forem/maker), které se používají i při běžném programování – jinými slovy to znamená, že jazyk maker je stále jazykem, v němž se zapisují programy (na rozdíl od zmíněného céčka a C++, kde je jazyk maker zcela odlišný). Jinými slovy to znamená, že se při tvorbě maker musíme seznámit pouze se způsobem zápisu maker, ale v samotných makrech se mohou používat funkce, které jsme si již v tomto článku popsali – většinou se bude jednat o funkce pro práci se seznamy, což je vzhledem ke způsobu reprezentace programů (jako do sebe vnořených seznamů) pochopitelné.

Poznámka: tato vlastnost se nazývá homoikonicita a v důsledku znamená, že dialekty LISPu vlastně stojí na vrcholu hierarchie programovacích jazyků. Jakoukoli novou sémantickou konstrukci, která se objeví v jiném programovacím jazyku, je totiž možné díky homoikonicitě implementovat i v LISPech (za předpokladu že LISP je Turingovsky úplný, což bezpochyby je).

Do funkce eval je tedy možné předat pouze korektně zapsanou formu. V některých případech je však určitý výraz nebo i větší část programů dostupná pouze ve formě řetězce – ten může být přečten například ze souboru, zadán uživatelem v nějakém GUI dialogu atd. Problém nastane v případě, kdy se pokusíme tento řetězec předat funkci eval v domnění, že se předávaný řetězec „automagicky“ bude transformovat na korektní formu a ta se následně vyhodnotí.

Předpoklad, že eval bude jako svůj parametr akceptovat řetězec, může vycházet ze zkušeností vývojáře s jinými programovacími jazyky (nemusíme ostatně chodit daleko – takto se totiž chová přímo Python), kde tomu tak skutečně může být, ovšem v Hy a ani v dalších dialektech LISPu to neplatí a pro toto chování jsou i dobré důvody – mimo jiné i bezpečnost (a taktéž to, že parsování řetězce skutečně není prací pro eval). Podívejme se nyní, co se stane, pokud se pokusíme nechat vyhodnotit řetězec obsahující zápis korektní formy, ovšem pouze v textové podobě:

; vytvoření nové globální proměnné
; a přiřazení SEZNAMU do této proměnné
=> (setv hello-code '(print "Hello world!"))
 
; hodnotu proměnné (tedy obsah seznamu)
; lze samozřejmě kdykoli získat
=> hello-code
HyExpression([
  HySymbol('print'),
  HyString('Hello world!')])
 
; i když proměnná obsahuje seznam s korektním
; voláním funkce, není možné použít následující
; formu pro zavolání této funkce
=> (hello-code)
Traceback (most recent call last):
  File "/home/tester/.local/lib/python3.4/site-packages/hy/importer.py", line 201, in hy_eval
    return eval(ast_compile(expr, "<eval>", "eval"), namespace)
  File "<eval>", line 1, in <module>
TypeError: 'HyExpression' object is not callable
 
; namísto toho se musí použít funkce eval
=> (eval hello-code)
Hello world!

Obrázek 17: Použití eval v jazyku Hy.

14. Makra „quote“ a „syntax-quote“

Konečně se dostáváme k zajímavým a užitečným reader makrům. Jedno z nejdůležitějších a nejčastěji používaných maker se jmenuje quote a zapisuje se pomocí apostrofu. Toto makro zakazuje vyhodnocování seznamů, protože pokud by objekt reader načetl formu ve tvaru (a b c), předal by ji do funkce eval, kde by se tato forma vyhodnotila jako volání funkce a s parametry b a c. Pokud však reader načte formu '(a b c), ztransformuje ji do tvaru (quote (a b c)), přičemž quote je speciální forma zakazující vyhodnocení. Na většinu ostatních objektů kromě seznamů nemá makro quote většinou žádný vliv:

=> '42
HyInteger(42)
=> '(1 2 3)
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])
=> '[1 2 3]
HyList([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])
=> [1 2 3]
[1, 2, 3]
=> '(* 6 7)
HyExpression([
  HySymbol('*'),
  HyInteger(6),
  HyInteger(7)])
=> (* 6 7)
42

Kromě makra quote ještě objekt reader rozeznává poněkud komplikovanější makro nazývané syntax-quote, které se zapisuje pomocí zpětného apostrofu: `. Chování tohoto makra se liší podle toho, s jakým typem objektu je použito, ovšem ve všech případech se makro chová tak, aby nedocházelo k vyhodnocení jeho argumentů, popř. ani k vyhodnocení vnořených forem. V následujících příkladech dochází k jednoduchému zákazu vyhodnocení předané formy:

=> `42
HyInteger(42)
=> `(1 2 3)
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])
=> `[1 2 3]
HyList([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])

Další možnosti využití tohoto makra:

=> `(* 6 7)
HyExpression([
  HySymbol('*'),
  HyInteger(6),
  HyInteger(7)])
=> `(str "Hello" "world")
HyExpression([
  HySymbol('str'),
  HyString('Hello'),
  HyString('world')])
=> `[* seq str xyzzy neznamy]
HyList([
  HySymbol('*'),
  HySymbol('seq'),
  HySymbol('str'),
  HySymbol('xyzzy'),
  HySymbol('neznamy')])

Makro nazvané unquote, které se zapisuje pomocí znaku ~ (tilda) dokáže vynutit vyhodnocení určité části výrazu, a to tehdy, pokud je tento výraz umístěn v makru ` (syntax-quote), nikoli však ' (quote). Nejprve si ukažme způsob zápisu tohoto makra i to, jaký má toto makro vliv na zapisované výrazy:

; makro quote zakáže vyhodnocení celého seznamu
=> '(1 2 (* 6 7) (/ 4 2))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyExpression([
    HySymbol('*'),
    HyInteger(6),
    HyInteger(7)]),
  HyExpression([
    HySymbol('/'),
    HyInteger(4),
    HyInteger(2)])])
 
; makro syntax-quote zakáže vyhodnocení celého seznamu
=> `(1 2 (* 6 7) (/ 4 2))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyExpression([
    HySymbol('*'),
    HyInteger(6),
    HyInteger(7)]),
  HyExpression([
    HySymbol('/'),
    HyInteger(4),
    HyInteger(2)])])

Použití ~ uvnitř makra ` je taktéž možné a dokonce velmi často používané:

; pomocí ~ vynutíme vyhodnocení podvýrazu (* 6 7)
=> `(1 2 ~(* 6 7) (/ 4 2))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  42,
  HyExpression([
    HySymbol('/'),
    HyInteger(4),
    HyInteger(2)])])
 
; pomocí ~ vynutíme vyhodnocení podvýrazu (/ 4 2)
=> `(1 2 (* 6 7) ~(/ 4 2))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyExpression([
    HySymbol('*'),
    HyInteger(6),
    HyInteger(7)]),
  2.0])
 
; pomocí dvou ~ vynutíme vyhodnocení obou podvýrazů
=> `(1 2 ~(* 6 7) ~(/ 4 2))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  42,
  2.0])

Podobným způsobem pracuje i makro ~@, ovšem to navíc ještě provádí „zplošťování seznamů“. Prozatím si chování tohoto makra ukážeme na velmi jednoduchém umělém příkladu:

; uživatelsky definovaný seznam
=> (setv s '(1 2 3))
 
=> '(1 2 3 (cons s s))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3),
  HyExpression([
    HySymbol('cons'),
    HySymbol('s'),
    HySymbol('s')])])
=> `(1 2 3 (cons s s))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3),
  HyExpression([
    HySymbol('cons'),
    HySymbol('s'),
    HySymbol('s')])])
=> `(1 2 3 ~(cons s s))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3),
  HyExpression([
    HyExpression([
      HyInteger(1),
      HyInteger(2),
      HyInteger(3)]),
    HyInteger(1),
    HyInteger(2),
    HyInteger(3)])])
=> `(1 2 3 ~@(cons s s))
HyExpression([
  HyInteger(1),
  HyInteger(2),
  HyInteger(3),
  HyExpression([
    HyInteger(1),
    HyInteger(2),
    HyInteger(3)]),
  HyInteger(1),
  HyInteger(2),
  HyInteger(3)])

Obrázek 18: Makra „quote“ a „syntax-quote“.

15. Praktické použití – jednoduchá makra vytvořená v jazyku Hy

Uživatelská makra se vytváří s využitím defmacro. Podívejme se nyní na velmi jednoduché makro, které po svém zavolání (v době zpracování vstupního textu!) provede expanzi na (print 'výraz), tj. vypíše se původní (nevyhodnocený!) výraz, což se může hodit například při ladění programů:

(defmacro print-expression-1
    [expression]
    `(print '~expression))

Makro můžeme upravit i takovým způsobem, aby se nejprve vypsal nevyhodnocený výraz a posléze i jeho výsledek. Použijeme zde speciální formu do pro spojení většího množství funkcí do jediného bloku. Povšimněte si, že celý blok je uvozen zpětným apostrofem a uvnitř bloku tedy můžeme využít ~:

(defmacro print-expression-2
    [expression]
    `(do (print '~expression)
         (print ~expression)))

Příklady použití právě nadefinovaného makra print-expression-2:

(print-expression-1 (* 6 7))
 
HyExpression([
  HySymbol('*'),
  HyInteger(6),
  HyInteger(7)])
 
 
(print-expression-2 (* 6 7))
 
HyExpression([
  HySymbol('*'),
  HyInteger(6),
  HyInteger(7)])
42

Další makro nalezneme v doplňkové knihovně jazyka Hy. Umožňuje pro každý prvek seznamu zavolat nějakou funkci, která může mít vedlejší efekt. Uvnitř této funkce je příslušný prvek seznamu představován symbolem it. Makro nazvané ap-each vypadá následovně a jeho chování při expanzi je zřejmý, protože známe význam ` ~ i ~@:

(defmacro ap-each [lst &rest body]
  `(for [it ~lst] ~@body))

Příklad použití:

=> (ap-each [1 2 3] (print it))
1
2
3
 
=> (ap-each [1 2 3] (print (* it it)))
1
4
9

Obrázek 19: Dvě užitečná makra spuštěná přímo v prostředí Jupyter Notebooku.

16. Spuštění samotného interpretru jazyka Hy a práce s interaktivní smyčkou REPL

Interpret programovacího jazyka Hy není dostupný pouze z Jupyter Notebooku. Můžeme ho spustit i samostatně, a to velmi jednoduše: příkazem hy. Tento příkaz podporuje několik přepínačů, z nichž nejzajímavější je –spy, o němž se zmíníme v dalším textu:

$ hy --help
 
usage: hy [-h | -v | -i CMD | -c CMD | -m MODULE | FILE | -] [ARG]...
 
optional arguments:
-h, --help
    show this help message and exit
-c=COMMAND
    program passed in as a string (terminates option list)
-m=MOD
    module to run, passed in as a string (terminates option list)
-E
    ignore PYTHON* environment variables
-B
    don't write .py[co] files on import; also PYTHONDONTWRITEBYTECODE=x
-i=ICOMMAND
    program passed in as a string, then stay in REPL (terminates option list)
--spy
    print equivalent Python code before executing
--repl-output-fn=REPL_OUTPUT_FN
    function for printing REPL output (e.g., hy.contrib.hy-repr.hy-repr)
-v, --version
    show program's version number and exit
 
FILE
  program read from script
-
  program read from stdin
[ARG]...
  arguments passed to program in sys.argv[1:]

Zkusme si nyní interpret spustit a získat tak přístup k interaktivní smyčce REPL. Interpret se spustí prakticky okamžitě (na rozdíl od klasického Clojure založeného na JVM, kde je prodleva již patrnější – sekundy a v některých případech i desítky sekund). Výzva interpretru (prompt) se skládá ze znaků ⇒ (opět na rozdíl od Clojure bez uvedení výchozího jmenného prostoru):

$ hy
 
hy 0.20.0 using CPython(default) 3.6.6 on Linux
=>

V interaktivní smyčce je každý výraz po svém načtení (Read) ze standardního vstupu ihned vyhodnocen (Eval) a výsledná hodnota je následně vypsána do terminálu (Print) a interpret bude očekávat načtení dalšího výrazu (Loop). Některé výrazy jsou jednoduché, protože se vyhodnotí samy na sebe. Příkladem mohou být numerické hodnoty, pravdivostní hodnoty, řetězce atd:

=> 42
42
 
=> 3.1415
3.1415
 
=> 1+2j
(1+2j)
 
=> 6j
6j
 
=> 4/7
Fraction(4, 7)
 
=> True
True
 
=> False
False
 
=> None
 

Volba –spy umožňuje zjisit, jakým způsobem je kód z Hy transformován do Pythonu před vypsáním výsledku výrazu:

=> (+ 10 20)
10 + 20
30
 
 
=> (setv x 10)
x = 10
None
 
 
=> (setv y 20)
y = 20
None
 
 
=> (+ x y)
x + y
30
 
 
=> (setv z [1 2 3])
z = [1, 2, 3]
None
 
 
=> (assoc z 4 4)
z[4] = 4
None

Dále je možné s využitím nástrojů nazvaných hy2py a hy2py3 lze provést překlad zdrojových kódů naprogramovaných v jazyce Hy do Pythonu 2 či do Pythonu 3. Možnosti těchto nástrojů si ukážeme na třech variantách výpočtu faktoriálu. Povšimněte si, že výsledkem jsou většinou velmi pěkně čitelné zdrojové kódy, což při transpřekladu není vždy zvykem:

; nerekurzivní výpočet faktoriálu
 
(defn factorial
    [n]
    (if (neg? n)
        (raise (ValueError "natural number expected"))
        (reduce * (range 1 (inc n)))))
 
(print (factorial 10))
 
(for [n (range 1 11)]
     (print n (factorial n)))
 
(print (factorial -10))

Výsledek přeložený nástrojem hy2py3 – příkaz od příkazu obdoba předchozího skriptu:

from hy.core.language import inc, is_neg, reduce
from hy.core.shadow import *
 
 
def factorial(n):
    if is_neg(n):
        raise ValueError('natural number expected')
        _hy_anon_var_1 = None
    else:
        _hy_anon_var_1 = reduce(*, range(1, inc(n)))
    return _hy_anon_var_1
 
 
print(factorial(10))
for n in range(1, 11):
    print(n, factorial(n))
print(factorial(-10))

17. Dodatek: dostupné kernely pro Jupyter Notebook

V tomto dodatku jsou vypsány kernely, které jsou dostupné pro projekt Jupyter Notebook a které uživatelům nabízí vazbu na různé programovací jazyky. V kontextu dnešního článku zajímavé kernely jsou zvýrazněny:

Hacking tip

Kernel Jazyk
Dyalog Jupyter Kernel APL (Dyalog)
Coarray-Fortran Fortran 2008/2015
IJulia Julia
IHaskell ghc >= 7.6
IRuby ruby >= 2.3
tslab Typescript 3.7.2, JavaScript ESNext
IJavascript nodejs >= 0.10
ITypeScript Typescript >= 2.0
jpCoffeescript coffeescript >= 1.7
jp-LiveScript livescript >= 1.5
ICSharp C# 4.0+
IFSharp F#
lgo Go >= 1.8
iGalileo Galileo >= 0.1.3
gopherlab Go >= 1.6
Gophernotes Go >= 1.9
IScala Scala
IErlang Erlang
ITorch Torch 7 (LuaJIT)
IElixir Elixir >= 1.5
ierl Erlang >= 19, Elixir >= 1.4, LFE 1.2
OCaml-Jupyter OCaml >= 4.02
IForth Forth
peforth Forth
IPerl Perl 5
Perl6 Perl 6.c
IPerl6 Perl 6
Jupyter-Perl6 Perl 6.C
IPHP PHP >= 5.4
Jupyter-PHP PHP >= 7.0.0
IOctave Octave
IScilab Scilab
MATLAB Kernel Matlab
Bash bash
Z shell zsh >= 5.3
PowerShell PowerShell
CloJupyter Clojure >= 1.7
jupyter-kernel-jsr223 Clojure 1.8
Hy Kernel Hy
Calysto Hy Hy
jp-babel Babel
Lua Kernel Lua
IPurescript Purescript
IPyLua Lua
ILua Lua
Calysto Scheme Scheme
Calysto Processing Processing.js >= 2
idl_kernel IDL
Mochi Kernel Mochi
Lua (used in Splash) Lua
Calysto Bash bash
IBrainfuck Brainfuck
cling C++
xeus-cling C++
Prolog Prolog
SWI-Prolog SWI-Prolog
cl-jupyter Common Lisp
common-lisp-jupyter Common Lisp
IJython Jython 2.7
ROOT C++/python
Tcl Tcl 8.5
J J 805–807 (J901beta)
Jython Jython>=2.7.0
C C
Coconut Coconut
Pike Pike >= 7.8
jupyter-kotlin Kotlin 1.1-M04 EAP
mit-scheme-kernel MIT Scheme 9.2
elm-kernel elm
SciJava Jupyter Kernel Java + 9 scripting languages
BeakerX Groovy, Java, Scala, Clojure, Kotlin, SQL
IJava Java 9
Guile Guile 2.0.12
IRacket Racket >= 6.10
EvCxR Jupyter Kernel Rust >= 1.29.2
SSH Kernel Bash
Emu86 Kernel Intel Assembly Language

18. Předchozí články o Jupyter Notebooku

Se samotným nástrojem Jupyter Notebook jsme se již na stránkách Rootu několikrát setkali (až již přímo či nepřímo), a to konkrétně v následujících článcích:

  1. Gophernotes: kombinace interaktivního prostředí Jupyteru s jazykem Go
    https://www.root.cz/clanky/gophernotes-kombinace-interaktivniho-prostredi-jupyteru-s-jazykem-go/
  2. Jupyter Notebook – nástroj pro programátory, výzkumníky i lektory
    https://www.root.cz/clanky/jupyter-notebook-nastroj-pro-programatory-vyzkumniky-i-lektory/
  3. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib/
  4. Tvorba grafů v Jupyter Notebooku s využitím knihovny Matplotlib (dokončení)
    https://www.root.cz/clanky/tvorba-grafu-v-jupyter-notebooku-s-vyuzitim-knihovny-matplotlib-dokonceni/
  5. Jupyter Notebook – operace s rastrovými obrázky a UML diagramy, literate programming
    https://www.root.cz/clanky/jupyter-notebook-operace-s-rastrovymi-obrazky-a-uml-diagramy-literate-programming/
  6. Interpret programovacího jazyka Clojure integrovaný do Jupyter Notebooku
    https://www.root.cz/clanky/interpret-programovaciho-jazyka-clojure-integrovany-do-jupyter-notebooku/
  7. Programovací jazyk R, Jupyter notebook a Jupytext
    https://www.root.cz/clanky/pro­gramovaci-jazyk-r-jupyter-notebook-a-jupytext/

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

Všechny demonstrační příklady, resp. přesněji řečeno diáře pro Jupyter Notebook a kernel jazyka Hy, byly uloženy do repositáře, který naleznete na adrese https://github.com/tisnik/jupyter-notebook-examples:

# Notebook/skript Popis Odkaz
1 Calysto Hy #1 – základní datové typy.ipynb základní datové typy jazyka Hy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #1 – základní datové typy.ipynb
2 Calysto Hy #2 – numerické hodnoty.ipynb práce s numerickými hodnotami v Hy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #2 – numerické hodnoty.ipynb
3 Calysto Hy #3 – řetězce.ipynb jazyk Hy a řetězce https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #3 – řetězce.ipynb
4 Calysto Hy #4 – here dokumenty.ipynb here dokumenty v jazyku Hy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #4 – here dokumenty.ipynb
5 Calysto Hy #5 – zpracování vektorů.ipynb zpracování vektorů https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #5 – zpracování vektorů.ipynb
6 Calysto Hy #6 – práce se slovníky.ipynb práce se slovníky https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #6 – práce se slovníky.ipynb
7 Calysto Hy #7 – Python interop.ipynb volání funkcí a metod Pythonu https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #7 – Python interop.ipynb
8 Calysto Hy #8 – Numpy.ipynb práce s knihovnou Numpy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #8 – Numpy.ipynb
9 Calysto Hy #9 – makra.ipynb makra v jazyku Hy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #9 – makra.ipynb
10 Calysto Hy #10 – makra.ipynb makra v jazyku Hy https://github.com/tisnik/jupyter-notebook-examples/tree/master/calysto_hy/Calysto Hy #10 – makra.ipynb

20. Odkazy na Internetu

  1. Calysto Hy
    https://github.com/Calysto/calysto_hy
  2. Calysto Scheme
    https://github.com/Calysto/ca­lysto_scheme
  3. Calysto Metakernel
    https://github.com/Calysto/metakernel
  4. Calysto Hy Notebooks: Tutorial.ipynb
    https://github.com/Calysto/ca­lysto_hy/blob/master/note­books/Tutorial.ipynb
  5. Python becomes a platform
    https://khinsen.wordpress­.com/2012/03/15/python-becomes-a-platform/
  6. Python becomes a platform. Thoughts on the release of clojure-py
    https://news.ycombinator.com/i­tem?id=3708974
  7. SchemePy
    https://pypi.org/project/SchemePy/
  8. lispy
    https://pypi.org/project/lispy/
  9. Lython
    https://pypi.org/project/Lython/
  10. Lizpop
    https://pypi.org/project/lizpop/
  11. Budoucnost programovacích jazyků
    http://www.knesl.com/budoucnost-programovacich-jazyku
  12. LISP Prolog and Evolution
    http://blog.samibadawi.com/2013/05/lisp-prolog-and-evolution.html
  13. List of Lisp-family programming languages
    https://en.wikipedia.org/wi­ki/List_of_Lisp-family_programming_languages
  14. clojure_py na indexu PyPi
    https://pypi.python.org/py­pi/clojure_py
  15. PyClojure
    https://github.com/eigenhom­bre/PyClojure
  16. Hy na GitHubu
    https://github.com/hylang/hy
  17. Hy: The survival guide
    https://notes.pault.ag/hy-survival-guide/
  18. Hy běžící na monitoru terminálu společnosti Symbolics
    http://try-hy.appspot.com/
  19. Welcome to Hy’s documentation!
    http://docs.hylang.org/en/stable/
  20. Hy na PyPi
    https://pypi.org/project/hy/#des­cription
  21. Getting Hy on Python
    https://lwn.net/Articles/596626/
  22. Programming Can Be Fun with Hy
    https://opensourceforu.com/2014/02/pro­gramming-can-fun-hy/
  23. Přednáška o projektu Hy (pětiminutový lighttalk)
    http://blog.pault.ag/day/2013/04/02
  24. Hy (Wikipedia)
    https://en.wikipedia.org/wiki/Hy
  25. Clojure home page
    http://clojure.org/
  26. Clojure Sequences
    http://clojure.org/sequences
  27. Clojure Data Structures
    http://clojure.org/data_structures
  28. Clojure
    https://en.wikipedia.org/wiki/Clojure
  29. How to create Clojure notebooks in Jupyter
    https://s01blog.wordpress­.com/2017/12/10/how-to-create-clojure-notebooks-in-jupyter/
  30. Dokumentace k nástroji Conda
    https://docs.conda.io/en/latest/
  31. Notebook interface
    https://en.wikipedia.org/wi­ki/Notebook_interface
  32. Matplotlib Home Page
    http://matplotlib.org/
  33. Matplotlib (Wikipedia)
    https://en.wikipedia.org/wi­ki/Matplotlib
  34. Popis barvových map modulu matplotlib.cm
    https://gist.github.com/en­dolith/2719900#id7
  35. Ukázky (palety) barvových map modulu matplotlib.cm
    http://matplotlib.org/exam­ples/color/colormaps_refe­rence.html
  36. Galerie grafů vytvořených v Matplotlibu
    https://matplotlib.org/3.2.1/gallery/
  37. showcase example code: xkcd.py
    https://matplotlib.org/xkcd/e­xamples/showcase/xkcd.html
  38. Customising contour plots in matplotlib
    https://philbull.wordpres­s.com/2012/12/27/customising-contour-plots-in-matplotlib/
  39. Graphics with Matplotlib
    http://kestrel.nmt.edu/~ra­ymond/software/python_notes/pa­per004.html
  40. The IPython Notebook
    http://ipython.org/notebook.html
  41. nbviewer: a simple way to share Jupyter Notebooks
    https://nbviewer.jupyter.org/
  42. Back to the Future: Lisp as a Base for a Statistical Computing System
    https://www.stat.auckland­.ac.nz/~ihaka/downloads/Com­pstat-2008.pdf
  43. gg4clj: a simple wrapper for using R's ggplot2 in Clojure and Gorilla REPL
    https://github.com/JonyEpsilon/gg4clj
  44. Analemma: a Clojure-based SVG DSL and charting library
    http://liebke.github.io/analemma/

Autor článku

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