Obsah
1. Clojure pro JVM, CLR i virtuální stroje JavaScriptu
2. Programovací jazyk Pixie aneb „Clojure bez JVM“
3. Překlad interpretru a JITu jazyka Pixie
4. Kontrola, zda jsou nainstalovány všechny potřebné knihovny
5. Spuštění interpretru (smyčky REPL)
6. Strukturované datové typy (kolekce)
7. Základní operace nad strukturovanými datovými typy (kolekcemi)
10. Podpora pro práci se zlomky a čísly s neomezeným rozsahem
12. Atomy a strukturované datové typy
13. Odkazy na předchozí části tohoto seriálu
1. Clojure pro JVM, CLR i virtuální stroje JavaScriptu
„That is to say, if you're doing lightweight scripting, or want something that boots fast and runs well on low-end systems, Pixie might be a good fit. Basically I want it for all those times I'd reach for Python instead of Clojure.“
Autor programovacího jazyka Pixie.
Programovací jazyk Clojure v současnosti oficiálně existuje ve třech variantách. Pravděpodobně nejpoužívanější varianta je určena pro běh nad JVM (virtuálním strojem jazyka Java, Java Virtual Machine), dále existuje varianta pro CLR (Common Language Runtime z .NET) a třetí variantou je ClojureScript transformovaný do JavaScriptu a tedy využitelný například ve webových prohlížečích či v běhovém prostředí Node.js. Všechny tři zmíněné varianty mají jednu společnou vlastnost – spuštění a inicializace vlastního virtuálního stroje je poměrně zdlouhavé, což je kritické zejména na méně výkonných zařízeních (IoT). To mj. znamená, že se Clojure (ale například ani Java, Jython či Ruby) příliš často nepoužívá k psaní nástrojů, které mají běžet relativně krátkou dobu a mají být spouštěny z příkazové řádky. Existují sice řešení, které se snaží neustálé spouštění virtuálního stroje obejít (dobrým příkladem je projekt Nailgun), ovšem to neřeší vlastní problém; ten se pouze více či méně úspěšně obchází.
2. Programovací jazyk Pixie aneb „Clojure bez JVM“
„…the first language I ever wrote was when I was in high-school. It was a small interpreted language named PhaLinks and was terrible, but I learned a lot from the effort. I also acquired a distaste for parsers in the process. Which, incidentally, is why I stick with Lisp these days: Lisp parsers are super easy to write.“
Autor programovacího jazyka Pixie.
Pokud programátoři, kteří propadli kouzlu programovacího jazyka Clojure, potřebují kromě aplikací běžících delší dobu (webový server atd.) vytvářet i kratší skripty spouštěné typicky z příkazové řádky, nezbývá jim nic jiného, než se poohlédnout po alternativních řešeních a jazycích, které se (alespoň prozatím) Clojure pouze podobají a nejsou s ním vždy na 100% kompatibilní. Prozatím pravděpodobně nejpropracovanější variantou je jazyk nazvaný Pixie. Jazyk Pixie využívá just in time překladač (JIT) i správce paměti implementovaný v PyPy, další části Pixie jsou pak psány v jazycích C a C++.
Na rozdíl od Clojure, které se spoléhá na to, že programátoři budou využívat knihovny kompatibilní s vybraným virtuálním strojem (tj. například javovskou standardní knihovnu apod.) se jazyk Pixie spoléhá na rozhraní FFI (Foreign Function Interface) a tím pádem na použití nativních knihoven dostupných v operačním systému, v němž aplikace poběží. Kombinace JITu a GC z PyPy společně s nativními knihovnami se ukazuje být úspěšná, protože skripty psané v Pixie bez výkonnostních problémů fungují i na prvních modelech Raspberry Pi (to se týká i prakticky okamžitého spouštění).
Poznámka: Pixie není v žádném případě prvním programovacím jazykem, který se do jisté míry snaží napodobit programovací jazyk Clojure. V tomto seriálu jsme se již setkali s programovacím jazykem Wisp, který je automaticky s využitím takzvaného transpileru transformován do JavaScriptu, dále existuje sémanticky podobný jazyk naprogramovaný v Perlu atd. Ovšem Pixie je z těchto jazyků nejpropracovanější a především pak prakticky využitelný.
3. Překlad interpretru a JITu jazyka Pixie
Všechny dále uvedené příklady byly spouštěny a odzkoušeny na poslední verzi jazyka Pixie přeloženého ze zdrojových kódů získaných na GitHubu z repositáře https://github.com/pixie-lang/pixie (větev master). Vzhledem k tomu, že se tento jazyk poměrně rychle vyvíjí, je lepší provést překlad Pixie právě z oficiálního repositáře a nepoužívat velmi pravděpodobně zastaralou verzi z vaší linuxové distribuce. Ve skutečnosti není překlad příliš složitý, pouze poměrně zdlouhavý. Navíc vám k urychlení překladu příliš nepomůže procesor s větším množstvím jader, protože podstatná část překladu probíhá v jediném vláknu.
Prvním krokem je instalace všech potřebných knihoven:
- libffi-dev
- libedit-dev
- libuv-dev
- libboost-dev
Dále je nutné, aby byl na systému nainstalován interpret Pythonu (2), což je však s velkou pravděpodobností na prakticky všech distribucích splněno.
Další závislosti:
- Překladač jazyka C (gcc)
- Překladač jazyka C++ (g++)
- Nástroj Make
Dejte si prosím pozor na to, že pokud není nainstalován překladač jazyka C++, může překlad vypadat zdánlivě v pořádku, protože chybová hlášení relativně rychle „odscrollují“, ovšem překlad pokračuje dále.
O vlastní překlad se postará nástroj Make, překlad se spustí takto:
make build_with_jit
V první fázi překladu dochází ke stažení dalších balíčků potřebných pro sestrojení virtuálního stroje jazyka Pixie. Nelekněte se tedy, že se stahuje například poměrně objemný tarball obsahující PyPy z adresy https://bitbucket.org/pypy/pypy/get/91db1a9.tar.bz2.
V průběhu překladu dochází mj. i k ladění parametrů JITu, takže se nelekněte, když se při překladu začnou na terminál vykreslovat různé fraktály atd. (viz též přiložené screenshoty).
Výsledkem překladu by měl být spustitelný soubor nazvaný pixie-vm o velikosti přibližně 11 MB (což je stále o mnoho méně, než je velikost JVM z JRE). Pro úspěšné spuštění interpretru dále potřebujete adresář pixie; ostatní adresáře jsou potřebné jen pro otestování či pro překlad.
4. Kontrola, zda jsou nainstalovány všechny potřebné knihovny
Typický problém, na který můžete narazit až po překladu interpretru, je chybějící knihovna libedit-dev. Pokud tato knihovna není nainstalována (skutečně se jedná o -dev variantu), vypíše se při pokusu o start interpretru následující chybové hlášení:
./pixie-vm in internal function run_load_stdlib in internal function load-ns in internal function load-file in pixie function _toplevel_ in pixie/stdlib.pxi at 14:14 (def libedit (ffi-library (str "libedit." pixie.platform/so-ext))) ^ in internal function ffi-library RuntimeException: <inst pixie.stdlib.Keyword> Couldn't Load Library: libedit.so
Podobné chybové hlášení se objeví ve chvíli, kdy není k dispozici knihovna libffi-dev. Ostatní závislosti jsou kontrolovány již v době překladu.
5. Spuštění interpretru (smyčky REPL)
Předpokládejme, že se virtuální stroj s interpretrem jazyka Pixie podařilo přeložit bez problémů. Zbývá nám si otestovat jeho základní funkcionalitu, takže si nejprve interpret spusťme:
./pixie-vm user =>
Spuštěním virtuálního stroje jsme se dostali do základního režimu interpretru – do interaktivní smyčky REPL (Read Eval Print Loop), v níž lze zadávat libovolné formy, které jsou ihned interpretovány. Syntaxe zápisu forem odpovídá syntaxi programovacího jazyka Clojure, což si ostatně můžeme velmi jednoduše vyzkoušet:
; vyhodnocení konstant user => 42 42 user => :foo :foo user => "Hello" "Hello" user => 1/2 1/2 user => nil nil ; volání funkcí vyhodnocujících základní aritmetické výrazy user => (* 6 7) 42 user => (* (+ 1 2 3) (- 4 5 6)) -42 ; většina funkcí ze standardní knihovny obsahuje dokumentační řetězce user => (doc +) pixie.stdlib/+ ([& args]) Adds the arguments, returning 0 if no arguments. nil user => (doc println) pixie.stdlib/println ([& args]) Prints the arguments, separated by spaces, with a newline at the end. nil user => (doc conj) pixie.stdlib/conj ([] [coll] [coll item] [coll item & args]) Adds elements to the collection. Elements are added to the end except in the case of Cons lists. nil
6. Strukturované datové typy (kolekce)
Programovací jazyk Pixie podporuje všechny základní strukturované datové typy, které známe z jazyka Clojure. Jedná se o seznamy, vektory, mapy i množiny:
# | Typ kolekce | Zápis (syntaktický cukr) | Konstruktor |
---|---|---|---|
1 | Seznam | (prvky) | '(prvky) (list prvky) |
2 | Vektor | [prvky] | (vector prvky) (vec kolekce) |
3 | Mapa | {dvojice klíč-hodnota} | (hash-map dvojice klíč-hodnota) |
4 | Množina | #{unikátní prvky} | (hash-set unikátní prvky) |
Konstruktory těchto typů zapisované s využitím „syntaktického cukru“ jsou taktéž shodné, ostatně se podívejme na příklady:
user => (def seznam '(1 2 3 'a 'b "hello")) <inst pixie.stdlib.Var> user => (type seznam) pixie.stdlib.Cons user => (def vektor [1 2 3 'a 'b "hello"]) <inst pixie.stdlib.Var> user => (type vektor) pixie.stdlib.PersistentVector user => (def mapa {:first "jedna" :second "dva"}) <inst pixie.stdlib.Var> user => (type mapa) pixie.stdlib.PersistentHashMap user => (def mnozina #{1 2 3}) <inst pixie.stdlib.Var> user => (type mnozina) pixie.stdlib.PersistentHashSet
Všechny tyto strukturované typy jsou neměnitelné (immutable), stejně jako je tomu v programovacím jazyku Clojure. Ostatně se jedná o jednu ze základních vlastností Clojure, která je – alespoň podle názoru autora tohoto článku – jedním z důležitých faktorů oblíbenosti tohoto jazyka.
Mezi další vlastnosti, které jsou společné všem kolekcím, patří:
- Kolekce jsou perzistentní.
- Mezi libovolným počtem kolekcí jazyk zajišťuje sdílení struktury, pokud je to možné.
- U všech kolekcí lze zjistit počet prvků funkcí count.
- Každá kolekce je mapovatelná na sekvenci a je tedy možné procházet všemi prvky kolekce.
- Ke každé kolekci je možné „přidat“ nový prvek funkcíconj, výsledkem je nová kolekce.
7. Základní operace nad strukturovanými datovými typy (kolekcemi)
Některé funkce nabízené jazykem Pixie jsou společné všem kolekcím. Ty nejužitečnější funkce jsou vypsány v následující tabulce. Povšimněte si, že některé funkce známé z jazyka Clojure, například funkce peek, zde nenajdeme (ovšem není problém si je v případě potřeby dodefinovat):
# | Funkce | Význam funkce |
---|---|---|
1 | count | vrátí počet prvků v kolekci |
2 | empty? | (s otazníkem na konci) vrátí true v případě, že je kolekce prázdná |
3 | empty | (bez otazníku) vrátí prázdnou kolekci stejného typu |
4 | not-empty? | pokud není parametrem prázdná kolekce, vrátí se tato kolekce, jinak se vrátí nil |
5 | cons | vrátí novou kolekci s přidaným prvkem (odkaz jazyka LISP) |
6 | pop | vrátí kolekci bez prvního prvku (seznamy) nebo bez prvku posledního (vektory) |
7 | nth | získání n-tého prvku kolekce |
8 | first | první prvek kolekce |
9 | rest | kolekce bez prvního prvku |
Tyto funkce si můžeme snadno vyzkoušet v interaktivní smyčce REPL:
user => (empty? [1 2 3]) false user => (empty? []) true user => (empty? {}) true user => (empty? {:prvni 1 :druhy 2}) false ; speciální případ, kdy nil nahrazuje prázdnou kolekci user => (empty? nil) true user => (count [1 2 3]) 3 user => (def seznam '(1 2 3)) <inst pixie.stdlib.Var> user => (def vektor [1 2 3]) <inst pixie.stdlib.Var> user => (conj seznam 100) (100 1 2 3) user => (conj vektor 100) [1 2 3 100] user => (pop [1 2 3]) [1 2] user => (nth [1 2 3] 1) 2 user => (first mnozina) 2 user => (first vektor) 1 user => (rest vektor) (2 3) user => (rest mnozina) (3 1)
U map lze použít i zkrácený zápis pro přečtení prvku uloženého pod nějakým klíčem:
user => (def mapa {:first "jedna" :second "dva"}) <inst pixie.stdlib.Var> user => (count mapa) 2 user => (get mapa :first) "jedna" user => (get mapa :blabla) nil user => (:first mapa) "jedna" user => (:foobar mapa) nil
Další užitečnou funkcí je funkce into, která dokáže převádět prvky mezi různými typy kolekcí. Například následující příklad převede sekvenci dvojic čísel na mapu, v níž jsou klíčem celá čísla 1 až 9 a hodnotami druhé mocniny těchto klíčů:
user => (into {} (for [x (range 1 10)] [x (* x x)])) {9 81, 8 64, 1 1, 3 9, 5 25, 2 4, 6 36, 7 49, 4 16}
8. Funkce vyššího řádu
V programovacím jazyku Pixie jsou samozřejmě podporovány i funkce vyššího řádu, ostatně jedná se o LISPovský jazyk, takže by se nemělo jednat o velké překvapení. Mezi základní funkce vyššího řádu patří zejména čtveřice map, apply, filter a reduce. Pojďme si nyní použití těchto funkcí otestovat.
Nejdříve vytvoříme sekvenci, přesněji řečeno speciální typ sekvence, pomocí funkce range:
user => (def a (range 1 10)) <inst pixie.stdlib.Var> user => a (1 2 3 4 5 6 7 8 9) user => (type a) Range
Funkce vyššího řádu reduce postupně aplikuje předanou funkci (zde konkrétně funkci +) na akumulovaný mezivýsledek a jednotlivé prvky sekvence (funkce musí akceptovat dva parametry). Sekvence je tedy postupně redukována v každé iteraci o jeden prvek:
user => (reduce + a) 45
Funkce apply naproti tomu převezme sekvenci (druhý parametr) a vytvoří z nich parametry funkce (první parametr). Výsledek sice bude v tomto případě stejný, ovšem pro jiné funkce to samozřejmě nemusí být pravda:
user => (apply + a) 45
Funkce vyššího řádu map dokáže pro každý prvek sekvence zavolat předanou funkci a vytvořit tak novou sekvenci. Zde konkrétně použijeme anonymní funkci (lambdu), která vynásobí svůj parametr dvěma:
user => (map #(* % 2) a) (2 4 6 8 10 12 14 16 18)
Užitečná je i funkce nazvaná filter, která z předané sekvence vybere pouze ty prvky, které odpovídají zadanému predikátu. Predikátem je libovolná funkce vracející pravdivostní hodnotu true či false (popř. nil, který se taktéž chápe jako false). My si vytvoříme nový predikát, kterým bude funkce testující, zda je parametr liché číslo:
user => (defn odd [x] (= 1 (rem x 2))) <inst pixie.stdlib.Var> user => (odd 1) true user => (odd 2) false
S využitím tohoto predikátu již můžeme z předané sekvence vyfiltrovat pouze liché prvky:
user => (filter odd a) (1 3 5 7 9)
Poslední zajímavou a užitečnou funkcí vyššího řádu je funkce take-while. Tato funkce se podobá funkci take, která z předané sekvence získá prvních n prvků:
; nekonečná sekvence (ve skutečnosti je tato sekvence v jazyku Pixie omezena) user => (def b (range)) user => (take 10 b) (0 1 2 3 4 5 6 7 8 9)
Funkce take-while namísto hodnoty n očekává predikát. Dokud predikát vrací hodnotu true, budou se prvky ze vstupní sekvence předávat do sekvence výstupní, při první hodnotě false je funkce ukončena. Tímto způsobem lze například získat ta celá čísla, jejichž druhá mocnina je menší než 100 popř. 1000:
user => (take-while #(< (* % %) 100) b) (0 1 2 3 4 5 6 7 8 9) user => (take-while #(< (* % %) 1000) b) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31)
Následují typické „školní“ příklady použití funkcí apply a reduce pro získání tabulky faktoriálů:
user => (doseq [n (range 1 11)] (println n (apply * (range 1 (inc n))))) 1 1 2 2 3 6 4 24 5 120 6 720 7 5040 8 40320 9 362880 10 3628800 nil
user => (doseq [n (range 1 11)] (println n (reduce * (range 1 (inc n))))) 1 1 2 2 3 6 4 24 5 120 6 720 7 5040 8 40320 9 362880 10 3628800 nil
9. Threading makra
V programovacím jazyku Clojure existuje dvojice velmi užitečných maker, která je možné použít pro zjednodušení zápisu „kolony“ funkcí, kterým se postupně předávají výsledky předchozích funkcí. Jedná se vlastně o obdobu klasické Unixové kolony používané při spojování filtrů v shellu (ls –1 | sort). V Clojure je možné namísto poměrně nečitelného zápisu (f (g (h x))) použít zápis (->x h g f), kterým se specifikuje, že se hodnota x předá funkci h, výsledek této funkce se předá funkci g a výsledek funkce g se předá funkci f.
Threading makro → přidá předchozí výsledek další funkci ve svém prvním parametru:
user => (def a (range 1 11)) <inst pixie.stdlib.Var> user => a (1 2 3 4 5 6 7 8 9 10) user => (-> a count) 10 user => (-> a count inc) 11
V mnoha případech nám však nemusí vyhovovat, že se předchozí výsledek předá další funkci v koloně v prvním parametru. Dobrým příkladem mohou být již výše zmíněné funkce vyššího řádu. Pokud se tyto funkce používají v koloně, musí se namísto makra → použít druhé threading makro nazvané ->>, které předchozí výsledek předá další funkci v posledním parametru, nikoli v parametru prvním:
user => (->> a (map #(* % 2))) (2 4 6 8 10 12 14 16 18 20) user => (->> a (map #(* % 2)) (reduce +)) 110 user => (->> a (filter #(< % 5)) (map #(* % 2))) (2 4 6 8)
Druhý příklad na threading makro ->>, které provede tyto operace:
- Vytvoří sekvenci deseti hodnot 0..9
- Vyfiltruje ze sekvence lichá čísla
- Prvky výsledné sekvence 1, 3, .. 9 vynásobí dvěma
user => (defn odd[x] (= 1 (rem x 2))) <inst pixie.stdlib.Var> user => (->> 10 range (filter odd) (map #(* 2 %))) (2 6 10 14 18)
10. Podpora pro práci se zlomky a čísly s neomezeným rozsahem
Podobně jako v naprosté většině ostatních LISPovských jazyků nalezneme i v programovacím jazyku Pixie podporu pro práci se zlomky (které tvoří samostatný datový typ, interně se jedná o dvojici celých čísel) i podporu pro práci s celočíselnými hodnotami s prakticky neomezeným rozsahem (rozsah je samozřejmě omezen kapacitou operační paměti, ovšem z praktického hlediska lze rozsah považovat za neomezený). Nejprve si ukažme práci se zlomky, které se zapisují tak, jak jsme zvyklí ze školy (znak „/“ zde samozřejmě neznamená operátor dělení):
user => 1/3 1/3 user => 1/2 1/2
Operace se zlomky se zapisují jednoduše. Povšimněte si, že po každé operaci se automaticky provede zjednodušení zlomku:
user => (+ 1/3 1/2) 5/6 user => (+ 1/2 1/4) 3/4 user => (* 2 (+ 1/2 1/4)) 3/2 user => (+ 1/2 (* 3/4 (/ 5/6 7/8))) 17/14
Další příklad: kombinace threading makra, konstruktoru sekvence, funkce vyššího řádu reduce a zlomků:
user => (->> (repeat 10 3/7) (reduce *)) 59049/282475249
Většinu problémů s datovým typem float/double lze tedy velmi snadno obejít právě použitím zlomků; samozřejmě však nesmíme zapomenout na to, že výpočty mohou být i řádově pomalejší.
Práce s celými čísly s neomezeným rozsahem je z pohledu programátora velmi jednoduchá. Jazyk Pixie se ve většině případů dokáže sám rozhodnout, kdy tento rozsah použít a kdy postačují prostá celá čísla (typu long integer). Povšimněte si odlišného typu následujících dvou hodnot:
user => (type 1) pixie.stdlib.Integer user => (type (* 10000000000 1000000000)) pixie.stdlib.BigInteger
Následuje poněkud extrémní příklad použití při výpočtu faktoriálu (namísto funkce apply lze použít i funkci reduce):
user => (type (apply * (range 1 1000))) pixie.stdlib.BigInteger user => (apply * (range 1 1000)) 402387260077093773543702433923003985719374864210714632543799 910429938512398629020592044208486969404800479988610197196058 631666872994808558901323829669944590997424504087073759918823 627727188732519779505950995276120874975462497043601418278094 646496291056393887437886487337119181045825783647849977012476 632889835955735432513185323958463075557409114262417474349347 553428646576611667797396668820291207379143853719588249808126 867838374559731746136085379534524221586593201928090878297308 431392844403281231558611036976801357304216168747609675871348 312025478589320767169132448426236131412508780208000261683151 027341827977704784635868170164365024153691398281264810213092 761244896359928705114964975419909342221566832572080821333186 116811553615836546984046708975602900950537616475847728421889 679646244945160765353408198901385442487984959953319101723355 556602139450399736280750137837615307127761926849034352625200 015888535147331611702103968175921510907788019393178114194545 257223865541461062892187960223838971476088506276862967146674 697562911234082439208160153780889893964518263243671616762179 168909779911903754031274622289988005195444414282012187361745 992642956581746628302955570299024324153181617210465832036786 906117260158783520751516284225540265170483304226143974286933 061690897968482590125458327168226458066526769958652682272807 075781391858178889652208164348344825993266043367660176999612 831860788386150279465955131156552036093988180612138558600301 435694527224206344631797460594682573103790084024432438465657 245014402821885252470935190620929023136493273497565513958720 559654228749774011413346962715422845862377387538230483865688 976461927383814900140767310446640259899490222221765904339901 886018566526485061799702356193897017860040811889729918311021 171229845901641921068884387121855646124960798722908519296819 372388642614839657382291123125024186649353143970137428531926 649875337218940694281434118520158014123344828015051399694290 153483077644569099073152433278288269864602789864321139083506 217095002597389863554277196742822248757586765752344220207573 630569498825087968928162753848863396909959826280956121450994 871701244516461260379029309120889086942028510640182154399457 156805941872748998094254742173582401063677404595741785160829 230135358081840096996372524230560855903700624271243416909004 153690105933983835777939410970027753472000000000000000000000 000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000N
11. Práce s atomy
Programovací jazyk Pixie podporuje práci se dvěma typy symbolů, na nichž může být navázána hodnota. Pokud se použije deklarace ve stylu:
(def Pi 3.1415)
je vytvořen symbol, na nějž je navázána konstantní hodnota, kterou nelze změnit (samozřejmě je možné symbol předefinovat, to však vede k neidiomatickému kódu). Pokud je zapotřebí pracovat s měnitelnými proměnnými, lze v jazyku Pixie použít takzvané atomy, které mají k proměnným pravděpodobně nejblíže. Zatímco však běžné proměnné může měnit jakékoli vlákno bez další koordinace s ostatními vlákny, jsou hodnoty atomů modifikovány „atomicky“ – ostatní vlákna uvidí buď starou hodnotu nebo hodnotu novou, nikdy ne výsledek nějakého mezivýpočtu.
Práce s atomy je v praxi velmi jednoduchá, protože si programátor vystačí se čtveřicí funkcí, k nimž můžeme připočíst ještě jedno makro preprocesoru. Všechny čtyři zmíněné funkce můžeme nalézt v následující tabulce:
# | Funkce | Význam |
---|---|---|
1 | atom | vytvoření reference typu atom |
2 | deref | dereference, vrátí se stav identity |
3 | reset! | atomická změna stavu identity na zvolenou hodnotu |
4 | swap! | atomická změna stavu identity zavoláním zvolené funkce |
Atomy se vytváří pomocí funkce atom, které lze předat počáteční (inicializační) hodnotu:
; vytvoření nového atomu user => (def i (atom 1)) <inst pixie.stdlib.Var> ; globální symbol i je navázán ; na atom a nikoli na stav identity ; (=hodnotu) user => i <inst pixie.stdlib.Atom> ; pro jistotu zkontrolujeme typ objektu user => (type i) pixie.stdlib.Atom
Způsob přečtení hodnoty:
; pro získání aktuálního stavu ; je nutné použít dereferenci user => (deref i) 1 ; namísto (deref x) se používá ; makro preprocesoru @ user => @i 1
; atomická změna stavu identity user => (reset! i 42) 42 ; další možnost atomické změny ; stavu identity - nyní přes funkci ; aplikovanou na atom a popř. i další ; parametry user => (swap! i inc) 43 ; samozřejmě lze použít i anonymní funkci user => (swap! i #(* % %)) 1849
12. Atomy a strukturované datové typy
Do atomů se samozřejmě nemusí ukládat jen číselné hodnoty, ale je možné použít i všechny podporované strukturované datové typy neboli kolekce. V dalším příkladu si ukážeme, jak je možné implementovat měnitelnou (mutable) mapu:
; vytvoření prázdné mapy (ta je sama o sobě immutable) a její uložení do atomu user => (def m (atom {})) <inst pixie.stdlib.Var> ; použití funkce swap! a assoc, funkce assoc vrátí novou mapu s přidaným prvkem user => (swap! m assoc :first "prvni") {:first "prvni"} ; dereference hodnoty uložené do atomu s využitím makra @ user => @m {:first "prvni"} ; přidání dalšího prvku do mapy user => (swap! m assoc :second "druhy") {:first "prvni", :second "druhy"} ; přidání třetího prvku do mapy user => (swap! m assoc :third "treti") {:first "prvni", :third "treti", :second "druhy"} ; odstranění dvou prvků specifikovaných svým klíčem z mapy user => (swap! m dissoc :first :second) {:third "treti"}
13. Odkazy na předchozí části tohoto seriálu
- Clojure 1: Úvod
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm/ - Clojure 2: Symboly, kolekce atd.
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-2-cast/ - Clojure 3: Funkcionální programování
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-3-cast-funkcionalni-programovani/ - Clojure 4: Kolekce, sekvence a lazy sekvence
http://www.root.cz/clanky/clojure-aneb-jazyk-umoznujici-tvorbu-bezpecnych-vicevlaknovych-aplikaci-pro-jvm-4-cast-kolekce-sekvence-a-lazy-sekvence/ - Clojure 5: Sekvence, lazy sekvence a paralelní programy
http://www.root.cz/clanky/clojure-a-bezpecne-aplikace-pro-jvm-sekvence-lazy-sekvence-a-paralelni-programy/ - Clojure 6: Podpora pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-6-futures-nejsou-jen-financni-derivaty/ - Clojure 7: Další funkce pro paralelní programování
http://www.root.cz/clanky/programovaci-jazyk-clojure-7-dalsi-podpurne-prostredky-pro-paralelni-programovani/ - Clojure 8: Identity, stavy, neměnné hodnoty a reference
http://www.root.cz/clanky/programovaci-jazyk-clojure-8-identity-stavy-nemenne-hodnoty-a-referencni-typy/ - Clojure 9: Validátory, pozorovatelé a kooperace s Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-9-validatory-pozorovatele-a-kooperace-mezi-clojure-a-javou/ - Clojure 10: Kooperace mezi Clojure a Javou
http://www.root.cz/clanky/programovaci-jazyk-clojure-10-kooperace-mezi-clojure-a-javou-pokracovani/ - Clojure 11: Generátorová notace seznamu/list comprehension
http://www.root.cz/clanky/programovaci-jazyk-clojure-11-generatorova-notace-seznamu-list-comprehension/ - Clojure 12: Překlad programů z Clojure do bajtkódu JVM I:
http://www.root.cz/clanky/programovaci-jazyk-clojure-12-preklad-programu-z-clojure-do-bajtkodu-jvm/ - Clojure 13: Překlad programů z Clojure do bajtkódu JVM II:
http://www.root.cz/clanky/programovaci-jazyk-clojure-13-preklad-programu-z-clojure-do-bajtkodu-jvm-pokracovani/ - Clojure 14: Základy práce se systémem maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-14-zaklady-prace-se-systemem-maker/ - Clojure 15: Tvorba uživatelských maker
http://www.root.cz/clanky/programovaci-jazyk-clojure-15-tvorba-uzivatelskych-maker/ - Clojure 16: Složitější uživatelská makra
http://www.root.cz/clanky/programovaci-jazyk-clojure-16-slozitejsi-uzivatelska-makra/ - Clojure 17: Využití standardních maker v praxi
http://www.root.cz/clanky/programovaci-jazyk-clojure-17-vyuziti-standardnich-maker-v-praxi/ - Clojure 18: Základní techniky optimalizace aplikací
http://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Clojure 19: Vývojová prostředí pro Clojure
http://www.root.cz/clanky/programovaci-jazyk-clojure-19-vyvojova-prostredi-pro-clojure/ - Clojure 20: Vývojová prostředí pro Clojure (Vimu s REPL)
http://www.root.cz/clanky/programovaci-jazyk-clojure-20-vyvojova-prostredi-pro-clojure-integrace-vimu-s-repl/ - Clojure 21: ClojureScript aneb překlad Clojure do JS
http://www.root.cz/clanky/programovaci-jazyk-clojure-21-clojurescript-aneb-preklad-clojure-do-javascriptu/ - Leiningen: nástroj pro správu projektů napsaných v Clojure
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (2)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-2/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (3)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-3/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (4)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-4/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (5)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-5/ - Leiningen: nástroj pro správu projektů napsaných v Clojure (6)
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-6/ - Programovací jazyk Clojure a databáze (1.část)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-databaze-1-cast/ - Pluginy pro Leiningen
http://www.root.cz/clanky/leiningen-nastroj-pro-spravu-projektu-napsanych-v-clojure-pluginy-pro-leiningen/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi/ - Programovací jazyk Clojure a knihovny pro práci s vektory a maticemi (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-knihovny-pro-praci-s-vektory-a-maticemi-2/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (2)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-2/ - Seesaw: knihovna pro snadnou tvorbu GUI v jazyce Clojure (3)
http://www.root.cz/clanky/seesaw-knihovna-pro-snadnou-tvorbu-gui-v-jazyce-clojure-3/ - Programovací jazyk Clojure a práce s Gitem
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem/ - Programovací jazyk Clojure: syntéza procedurálních textur s využitím knihovny Clisk (dokončení)
http://www.root.cz/clanky/programovaci-jazyk-clojure-synteza-proceduralnich-textur-s-vyuzitim-knihovny-clisk-dokonceni/ - Programovací jazyk Clojure a práce s Gitem (2)
http://www.root.cz/clanky/programovaci-jazyk-clojure-a-prace-s-gitem-2/ - Programovací jazyk Clojure – triky při práci s řetězci
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-retezci/ - Programovací jazyk Clojure – triky při práci s kolekcemi
http://www.root.cz/clanky/programovaci-jazyk-clojure-triky-pri-praci-s-kolekcemi/ - Programovací jazyk Clojure – práce s mapami a množinami
http://www.root.cz/clanky/programovaci-jazyk-clojure-prace-s-mapami-a-mnozinami/ - Programovací jazyk Clojure – základy zpracování XML
http://www.root.cz/clanky/programovaci-jazyk-clojure-zaklady-zpracovani-xml/ - Programovací jazyk Clojure – testování s využitím knihovny Expectations
http://www.root.cz/clanky/programovaci-jazyk-clojure-testovani-s-vyuzitim-knihovny-expectations/ - Programovací jazyk Clojure – některé užitečné triky použitelné (nejenom) v testech
http://www.root.cz/clanky/programovaci-jazyk-clojure-nektere-uzitecne-triky-pouzitelne-nejenom-v-testech/ - Enlive – výkonný šablonovací systém pro jazyk Clojure
http://www.root.cz/clanky/enlive-vykonny-sablonovaci-system-pro-jazyk-clojure/ - Nástroj Leiningen a programovací jazyk Clojure: tvorba vlastních knihoven pro veřejný repositář Clojars
http://www.root.cz/clanky/nastroj-leiningen-a-programovaci-jazyk-clojure-tvorba-vlastnich-knihoven-pro-verejny-repositar-clojars/ - Novinky v Clojure verze 1.8.0
http://www.root.cz/clanky/novinky-v-clojure-verze-1–8–0/ - Asynchronní programování v Clojure s využitím knihovny core.async
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async/ - Asynchronní programování v Clojure s využitím knihovny core.async (pokračování)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-pokracovani/ - Asynchronní programování v Clojure s využitím knihovny core.async (dokončení)
http://www.root.cz/clanky/asynchronni-programovani-v-clojure-s-vyuzitim-knihovny-core-async-dokonceni/ - Vytváříme IRC bota v programovacím jazyce Clojure
http://www.root.cz/clanky/vytvarime-irc-bota-v-programovacim-jazyce-clojure/ - Gorilla REPL: interaktivní prostředí pro programovací jazyk Clojure
https://www.root.cz/clanky/gorilla-repl-interaktivni-prostredi-pro-programovaci-jazyk-clojure/ - Multimetody v Clojure aneb polymorfismus bez použití OOP
https://www.root.cz/clanky/multimetody-v-clojure-aneb-polymorfismus-bez-pouziti-oop/ - Práce s externími Java archivy v programovacím jazyku Clojure
https://www.root.cz/clanky/prace-s-externimi-java-archivy-v-programovacim-jazyku-clojure/
14. Odkazy na Internetu
- Pixie (repositář na GitHubu)
https://github.com/pixie-lang/pixie - Pixie Installation
https://github.com/pixie-lang/pixie/wiki/Installation - Pixie Libraries
https://github.com/pixie-lang/pixie/wiki/Libraries - Interview with Timothy Baldridge, Pixie's language creator
https://notamonadtutorial.com/indie-languages-interview-pixie-and-timothy-baldridge-cadbc36418dc#.vhbl5rp1c - Pixie (programming language) [Wikipedia]
https://en.wikipedia.org/wiki/Pixie_%28programming_language%29 - Clojure home page
http://clojure.org/ - Clojure (downloads)
http://clojure.org/downloads - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc (rozcestník s dokumentací jazyka Clojure)
http://clojuredocs.org/ - Clojure (na Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (na Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - Clojars:
https://clojars.org/ - Seznam knihoven na Clojars:
https://clojars.org/projects - Zip archiv s Clojure 1.8.0
http://repo1.maven.org/maven2/org/clojure/clojure/1.8.0/clojure-1.8.0.zip - Clojure 1.8 is now available
http://clojure.org/news/2016/01/19/clojure18 - Changes to Clojure in Version 1.8
https://github.com/clojure/clojure/blob/master/changes.md - Clojure core.async
http://www.infoq.com/presentations/clojure-core-async - core.async API Reference
https://clojure.github.io/core.async/ - Clojure core.async Channels
http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html - core.async examples
https://github.com/clojure/core.async/blob/master/examples/walkthrough.clj - Timothy Baldridge – Core.Async
https://www.youtube.com/watch?v=enwIIGzhahw