Na trojici článků o transpřekladači jazyka Standard ML nazvaném LunarML [1] [2] [3] dnes navážeme, protože se budeme zabývat dalším programovacím jazykem z rodiny ML, do které spadá jak původní ML (Meta Language), tak i Standard ML, CAML (Categorical Abstract Machine Language), OCaml (Objective Caml), jazyk F# a do značné míry taktéž Haskell. Všechny tyto jazyky mají společné rysy: jsou funkcionální, mají podobný typový systém, využívají typovou inferenci, mají zabudovanou podporu pro pattern matching atd. Připomeňme si, že LunarML dokáže překládat, resp. přesněji řečeno transpřekládat zdrojové kódy napsané ve Standard ML do jazyka Lua a taktéž do JavaScriptu.
Co se dozvíte v článku
- Jazyk Elm – kombinace možností ML jazyka s prostředím JavaScriptu
- Nejdůležitější vlastnosti Elmu
- Jazyk Elm vs primární funkce JavaScriptových frameworků pro front end
- Je Elm mrtvým jazykem, který se dále nevyvíjí?
- Nechtěný důsledek: přesnější odpovědi získávané z velkých jazykových modelů
- Instalace interpretru a překladače jazyka Elm
- Použití interaktivní smyčky REPL
- Klávesové zkratky použitelné v REPLu
- Uživatelsky příjemná chybová hlášení překladače a interpretru
- Typový systém programovacího jazyka Elm
- Složené datové typy
- Standardní operátory, priorita a asociativita operátorů
- Definice funkcí a typová inference
- Funkce s větším počtem parametrů
- Příklady typových definic standardních funkcí
- Obsah navazujícího článku
- Literatura
- Předchozí články o jazyku ML/SML i o jazycích OCaml a F#
- Odkazy na Internetu
V dnešním článku se zaměříme právě na problematiku transpřekladu do JavaScriptu, protože mnoho v současnosti provozovaných či vyvíjených aplikací má svůj front end realizován ve webovém prohlížeči vybaveném právě interpretrem JavaScriptu (a navíc i virtuálním strojem pro WASM). Z tohoto důvodu je dobré mít k dispozici vhodné technologie, typicky transpřekladače, které umožní generovat zdrojový kód v JavaScriptu, jenž bude přímo spustitelný ve webovém prohlížeči. Takových transpřekladačů vzniklo minimálně několik desítek, možná i stovek.
Pravděpodobně nejznámější je transpiler jazyka TypeScript, který se snaží o řešení některých problémů typového systému JavaScriptu (a při té příležitosti jazyk dále vylepšuje, má mnohem lepší chybová hlášení apod.). I pro rodinu jazyků ML máme k dispozici podobné nástroje. O LunarML jsme se zmínili. Dále pro Standard ML existuje projekt SOSML (https://sosml.org/), což je interaktivní webové prostředí. Pro jazyk OCaml existuje projekt nazvaný js_of_ocaml neboli zkráceně jsoo. Nejedná se o samostatný transpřekladač, protože je nutné mít nainstalován prakticky celý ekosystém OCamlu (opam apod). A pro jazyk F# existuje (trans)překladač nazvaný Fable.
Jazyk Elm – kombinace možností ML jazyka s prostředím JavaScriptu
Všechny původní programovací jazyky z rodiny ML (tedy ML, Standard ML, CAML, OCaml, F#) byly navrženy takovým způsobem, že se jedná o překladače do nativního kódu popř. v případě jazyka F# do bajtkódu CLR (Common Language Runtime). Podpora pro prostředí JavaScriptu byla přidána až později a stále se jedná pouze o transpřekladač a nikoli o plnohodnotnou integraci vyžadovanou moderními webovými aplikacemi. V této situaci vznikl zcela nový programovací jazyk nazvaný Elm, který je přímo určen pro tvorbu webových aplikací (a tím pádem i pro kooperaci s prostředím JavaScriptu). Tento jazyk patří do rodiny ML, takže v něm nalezneme podobný typový systém i podobnou práci s chybějícími hodnotami a výjimkami.
Ovšem to není vše, protože Elm přímo podporuje manipulaci s DOMem webových stránek (DOM je představován základními datovými strukturami Elmu), je podporován návrhový vzor Model-View-Update atd. (ten je vlastně součástí samotného jazyka, nikoli frameworku). V tomto ohledu vznikla možná poněkud paradoxní situace – Elm je totiž lépe uzpůsoben tvorbě webových aplikací, než samotný JavaScript (který ke své roli přišel jako příslovečný slepý k houslím).
Ale to zdaleka není vše – samotný způsob použití Elmu je z pohledu uživatele-programátora velmi snadný a nevyžaduje další znalosti ekosystému JavaScriptu (balíčkovací nástroje, lokální interpretry atd.). Z tohoto pohledu je Elm velmi přívětivý. A nesmíme zapomenout ani na srozumitelná chybová hlášení, která kromě informace o chybě ukazují i na (předpokládaná) správná řešení. V tomto ohledu se Elm podobá Rustu; ve skutečnosti se Rust v této oblasti inspiroval právě Elmem.
Nejdůležitější vlastnosti Elmu
Poměrně mnoho vlastností programovacího jazyka Elm je odvozeno od klasických ML jazyků (vidět je například vliv OCamlu, ostatně i autor Elmu se zmiňuje o tom, že OCaml používal na universitě) a taktéž od Haskellu. Elm je funkcionální programovací jazyk, který nabízí silný typový systém doplněný o mechanismus typové inference. Kontroly prováděné překladačem mají za cíl zajistit stav, ve kterém nebude docházet k běhovým výjimkám způsobených například hodnotami nekorektních typů, neúplným pokrytím všech možných podmínek, které mohou nastat atd. Jedná se tedy o cíl, který má i programovací jazyk Rust. K dispozici jsou všechny potřebné datové typy, včetně Result, záznamů, seznamů, n-tic atd.
Elm navíc nabízí přímou manipulaci s objekty tvořícími HTML stránky, k čemuž používá mechanismus Model, View, Update určující a vlastně i řídicí, jakým způsobem bude HTML stránka „zaintegrována“ s vlastním programem (více si řekneme v samostatném článku). Díky tomu se Elm jakožto jazyk primárně určený pro tvorbu front endu (SPA) obejde bez nutnosti používání front end frameworku.
Samotná sada nástrojů jazyka Elm je vlastně minimalistická a nevyžaduje žádné další utility typu npm atd. Postačuje pouze stáhnout jediný binární soubor obsahující jak překladač, tak i interaktivní smyčku REPL, správce projektů apod. A když už mluvíme o překladači: jednalo se o jeden z prvních překladačů se skutečně „lidskými“ chybovými hlášeními, která v závislosti na kontextu obsahují i návod, jak chybu opravit (což dnes již není tak překvapivé a revoluční, ovšem před šesti lety to byla ukázka nového stylu).
Jazyk Elm vs primární funkce JavaScriptových frameworků pro front end
Ve světě JavaScriptu vzniklo velké množství různých frameworků určených pro tvorbu grafického uživatelského rozhraní (front end). Tyto frameworky jsou mnohdy interně velmi komplikované a nabízí vývojářům velké množství různých funkcí popř. komponent. Ovšem když se zamyslíme nad důvody existence těchto frameworků, je možné (s jistou, ale docela malou mírou nadsázky) tvrdit, že primárním účelem těchto frameworků je zajištění konzistence a synchronizace mezi vnitřním stavem aplikace na straně jedné a grafickým uživatelským rozhraním na straně druhé. Toho lze dosáhnout různými způsoby; od vlastně explicitní implementace synchronizace (API postavené na JSONu a RESTu) až po různé technologie pro konstrukci DOMu z dat.
Zajímavé je, že programovací jazyk Elm tuto důležitou funkcionalitu implementuje přímo jako součást jazyka, protože nabízí mechanismus nazvaný Model, View, Update. Podrobnosti si ukážeme v samostatném článku, protože se jedná o důležité téma. Výsledkem je, že i když Elm přímo slouží pro tvorbu uživatelského rozhraní, není nutné, aby pro něj vznikaly různé UI frameworky, protože jazyk sám nabízí potřebnou funkcionalitu.
Je Elm mrtvým jazykem, který se dále nevyvíjí?
„Old programming languages don’t die. Developers just get bored.“
Když přejdeme na stránky s Git repositářem překladače jazyka Elm nebo (možná ještě lépe) na stránku se seznamem oficiálně vydaných verzí, zjistíme, že se tento programovací jazyk vlastně prakticky vůbec dále nevyvíjí. Poslední oficiálně vydaná verze totiž nese číslo 0.19.1 a vydána byla už před sedmi (!) lety. To je v poměrně ostrém kontrastu s některými dalšími technologiemi, které se v informatice používají a u nichž platí, že pokud nebyla tento týden vydána nová verze (či alespoň oprava CVE), popř. pokud si autoři nějakého balíčku „dovolí“ vzít si krátkou dovolenou, považuje se to za téměř katastrofu.
Na „zakonzervování“ stavu Elmu se můžeme dívat z několika pohledů. Některé z nich byly zmíněny v článku o způsobech zajištění zpětné kompatibility v jazyku Go, který (zcela náhodou) na Rootu vyšel minulý týden. Jeden pohled říká, že technologie, která se přestane vyvíjet, je mrtvou technologií. Druhý pohled naopak poukazuje na existenci stabilních a stále používaných řešení postavených na COBOLu, FORTRANU 77 (ano, to je doba, kdy se ještě psal verzálkami), Fortranu 90, ANSI C, C99 atd. Nutno dodat, že některá řešení se prostě nevyplatí přepsat do modernějších jazyků. Elm můžeme z pohledu sémantiky považovat za jazyk, který nemá nutnost se dále vyvíjet, protože (zdá se) již obsahuje všechny důležité vlastnosti. U jiných jazyků tomu tak není – příkladem je Go, do kterého byly později přidány generické datové typy, neustále se diskutuje o způsobech zpracování chyb atd.
Nechtěný důsledek: přesnější odpovědi získávané z velkých jazykových modelů
Fakt, že se programovací jazyk Elm už přes šest let nachází v „zamrzlé“ fázi, má jeden zajímavý nechtěný (vlastně velmi pozitivní) důsledek: velké jazykové modely (LLM) většinou jazyk Elm dobře rozpoznávají a jejich odpovědi jsou přesné a platné pro jeho poslední verzi. Navíc jsou odpovědi jednoznačné i díky tomu, že Elm je jak programovací jazyk, tak i de facto svým způsobem front endový framework. Tj. otázky typu „jak vytvořit tlačítko zvyšující hodnotu o jedničku“ mají vždy jedinou jednoznačnou a v čase stabilní odpověď (která by v případě jiných ekosystémů byla do značné míry závislá jak na konkrétní verzi programovacího jazyka, tak i na použitém frameworku). To tedy znamená, že jazyk, který byl (prozatím) stabilizován již v roce 2019, velmi dobře zapadá do současného IT světa, kterému (zdá se) začínají do značné míry vládnout jazykové modely a na nich postavení agenti.
Instalace interpretru a překladače jazyka Elm
V případě, že striktně nevyžadujete překlad Elmu ze zdrojových kódů (přes ghc), je instalace Elmu až triviálně jednoduchá. Nejdříve se stáhne zazipovaný spustitelný soubor obsahující všechny potřebné nástroje:
$ wget https://github.com/elm/compiler/releases/download/0.19.1/binary-for-linux-64-bit.gz
Ve druhém kroku se za(g)zipovaný soubor rozbalí:
$ gunzip binary-for-linux-64-bit.gz
Výsledek:
$ ls -la -h binary-for-linux-64-bit -rw-r--r--. 1 ptisnovs ptisnovs 28M Dec 8 2021 binary-for-linux-64-bit
Otestujeme spuštěním získané „binárky“:
Hi, thank you for trying out Elm 0.19.1. I hope you like it!
-------------------------------------------------------------------------------
I highly recommend working through <https://guide.elm-lang.org> to get started.
It teaches many important concepts, including how to use `elm` in the terminal.
-------------------------------------------------------------------------------
The most common commands are:
binary-for-linux-64-bit repl
Open up an interactive programming session. Type in Elm expressions like
(2 + 2) or (String.length "test") and see if they equal four!
binary-for-linux-64-bit init
Start an Elm project. It creates a starter elm.json file and provides a
link explaining what to do from there.
binary-for-linux-64-bit reactor
Compile code with a click. It opens a file viewer in your browser, and
when you click on an Elm file, it compiles and you see the result.
There are a bunch of other commands as well though. Here is a full list:
binary-for-linux-64-bit repl --help
binary-for-linux-64-bit init --help
binary-for-linux-64-bit reactor --help
binary-for-linux-64-bit make --help
binary-for-linux-64-bit install --help
binary-for-linux-64-bit bump --help
binary-for-linux-64-bit diff --help
binary-for-linux-64-bit publish --help
Adding the --help flag gives a bunch of additional details about each one.
Be sure to ask on the Elm slack if you run into trouble! Folks are friendly and
happy to help out. They hang out there because it is fun, so be kind to get the
best results!
Použití interaktivní smyčky REPL
Výhody překladače, resp. přesněji řečeno překladače programovacího jazyka se silným typovým systémem (a do této kategorie Elm nepochybně patří), jsou pravděpodobně většině vývojářů zřejmé – výsledkem bývá vyšší rychlost běhu aplikací, obecně menší paměťové nároky procesů, na cílovém počítači nemusí být nainstalován žádný interpret a v neposlední řadě je poměrně velká část chyb (bohužel spíše těch triviálních) objevena již překladačem a nikoli v době běhu programu u uživatele nebo dokonce zákazníka.
Nicméně existují oblasti, v nichž se prosadil dosti odlišný způsob vývoje, který je založen na přímé interakci (resp. dialogu) mezi uživatelem a počítačem. V tom nejjednodušším (ale mnohdy velmi užitečném) případě se jedná o systémy vybavené interaktivní smyčkou REPL (Read Eval Print Loop), jejichž poněkud primitivní podobu si někteří mohou pamatovat z dob osmibitových mikropočítačů a interpretrů jazyka BASIC. Nicméně klasický REPL najdeme například i v Pythonu a dalších moderních skriptovacích jazycích (pro Python navíc existují různá jeho rozšíření, například v podobě IPythonu). V současnosti se mnohdy původní REPL nahrazuje spíše rozhraním ve stylu diáře (notebooku). Příkladem je projekt Jupyter Notebook, který v současnosti podporuje velké množství skriptovacích jazyků. A klasický REPL je dnes do jisté míry suplován i systémy s AI chaty (vibe coding apod. jako kontrast ke spec codingu).
Překladač jazyka Elm je vybaven plnohodnotnou interaktivní smyčkou REPL, která se inicializuje následujícím příkazem:
$ ./binary-for-linux-64-bit repl ---- Elm 0.19.1 ---------------------------------------------------------------- Say :help for help and :exit to exit! More at <https://elm-lang.org/0.19.1/repl> -------------------------------------------------------------------------------- >
Interakce uživatele s Elmem může vypadat takto:
---- Elm 0.19.1 ---------------------------------------------------------------- Say :help for help and :exit to exit! More at <https://elm-lang.org/0.19.1/repl> -------------------------------------------------------------------------------- > :help Valid commands include: :exit Exit the REPL :help Show this information :reset Clear all previous imports and definitions More info at <https://elm-lang.org/0.19.1/repl> > 6*7 42 : number > 6.0*7.0 42 : Float > :quit
Klávesové zkratky použitelné v REPLu
Jednou z důležitých vlastností (pro každodenní práci) je velké množství klávesových zkratek, které REPL programovacího jazyka Elm podporuje. Tyto zkratky jsou do značné míry odvozeny od GNU Readline a proto jsou v této kapitole vypsány vybrané klávesové zkratky, jenž jsou ve výchozím nastavení použity právě knihovnou GNU Readline při přepnutí do režimu Emacs. Tyto klávesové zkratky lze využít i v interaktivní smyčce REPL Elmu (což bylo pochopitelně otestováno).
Příkazy pro přesuny kurzoru
Základní příkazy pro přesun kurzoru používají klávesové kombinace Ctrl+znak, Alt+znak popř. alternativně Esc, znak v případě, že zkratky Alt+znak kolidují s emulátorem terminálu (například vyvolávají příkazy z menu). V případě, že je terminál správně nakonfigurován, měly by fungovat i kurzorové šipky a navíc i klávesy Home a End (se zřejmou funkcí):
| Klávesa | Význam |
|---|---|
| Ctrl+B | přesun kurzoru na předchozí znak |
| Ctrl+F | přesun kurzoru na další znak |
| Alt+B | přesun kurzoru na předchozí slovo |
| Alt+F | přesun kurzoru na následující slovo |
| Esc, B | shodné s Alt+B |
| Esc, F | shodné s Alt+F |
| Ctrl+A | přesun kurzoru na začátek řádku |
| Ctrl+E | přesun kurzoru na konec řádku |
Mazání textu, práce s kill ringem
Pro přesun části textu v rámci editovaného řádku s programovým kódem se používá takzvaný kill ring (to je termín převzatý z Emacsu), do něhož se smazaný text uloží. Pro vložení takto smazaného textu do jiné oblasti se používá operace nazvaná yank (odpovídá paste). Některé dále uvedené příkazy dokážou s kill ringem pracovat (asi nejčastější jsou kombinace Ctrl+K a Ctrl+Y):
| Klávesa | Význam |
|---|---|
| Ctrl+K | smaže text od kurzoru do konce řádku a uloží ho do kill ringu |
| Ctrl+U | smaže text od začátku řádku do pozice kurzoru a uloží ho do kill ringu |
| Ctrl+W | smaže předchozí slovo a uloží ho do kill ringu |
| Alt+D | smaže následující slovo a uloží ho do kill ringu |
| Ctrl+Y | vloží text z kill ringu na místo, na němž se nachází kurzor (yank) |
| Alt+Y | po operaci Ctrl+Y dokáže rotovat historií kill ringu a obnovit tak (před)předchozí smazaný text |
| Ctrl+D | smaže jeden znak (pokud je ovšem na řádku nějaký obsah, jinak typicky ukončí aplikaci) |
Práce s historií dříve zadaných příkazů
Z této skupiny příkazů je pravděpodobně nejznámější klávesová zkratka Ctrl+R, která slouží pro vyhledávání předchozích příkazů v historii:
| Klávesa | Význam |
|---|---|
| Ctrl+P | průchod historií – předchozí text |
| Ctrl+N | průchod historií – následující text |
| Ctrl+R | zpětné (interaktivní) vyhledávání v historii |
| Ctrl+G | ukončení režimu vyhledávání |
Některé další dostupné příkazy
A na závěr si uveďme některé další více či méně užitečné klávesové zkratky (z nějakého důvodu používám Ctrl+T častěji, než by možná bylo zdrávo):
| Klávesa | Význam |
|---|---|
| Tab | implicitní klávesa pro zavolání completeru |
| Ctrl+T | prohození dvou znaků (před kurzorem a na pozici kurzoru) |
| Alt+U | text od pozice kurzoru do konce slova se změní NA VERZÁLKY |
| Alt+L | text od pozice kurzoru do konce slova se změní na mínusky |
| Alt+C | text od pozice kurzoru do konce slova se změní Tak, Že Slova Začínají Velkým Písmenem |
Uživatelsky příjemná chybová hlášení překladače a interpretru
„Writing proper error messages is an art that every software developer should master.“
Jednou z nejpraktičtějších vlastností jazyka Elm jsou velmi čitelná chybová hlášení překladače. Při nalezení chyby se totiž vypíše nejenom informace o tom, k jaké chybě došlo, ale i v jakém kontextu byla chyba nalezena a taktéž návod, jak lze chybu napravit (ovšem pochopitelně není možné, aby byl překladač na sto procent úspěšný). Tento koncept je v oblasti IT relativně nový, protože několik desítek let (cca od padesátých let minulého století přibližně do roku 2012) bývala chybová hlášení překladačů velmi strohá a především – jednalo se skutečně o chybová hlášení a nikoli o snahu překladače naučit programátora korektnímu způsobu zápisu programů:
foo.map(1): Error: ':' expected foo.map(1): Error: Unexpected trailing garbage characters foo.map(3): Error: '.O' is not a recognized control command foo.map(4): Error: ':' expected foo.map(14): Error: Symbol 'AUTOSTRT' is already defined foo.map(14): Error: ':' expected foo.map(14): Error: Symbol '.size' is already defined foo.map(15): Error: Symbol 'EXEHDR' is already defined foo.map(15): Error: ':' expected foo.map(15): Error: Symbol '.size' is already defined foo.map(15): Error: Unexpected trailing garbage characters foo.map(16): Error: Symbol 'CODE' is already defined foo.map(16): Error: ':' expected
nebo:
1.c:1:3: error: expected declaration specifiers or ‘...’ before ‘;’ token 1.c:1:1: error: return type defaults to ‘int’ [-Wimplicit-int] 1.c: In function ‘m’: 1.c:1:6: error: stray ‘@’ in program 1.c:1:7: error: expected expression before ‘,’ token 1.c:1:8: error: ‘x’ undeclared (first use in this function) 1.c:1:8: note: each undeclared identifier is reported only once for each function it appears in 1.c:1:7: warning: left-hand operand of comma expression has no effect [-Wunused-value] 1.c: At top level: 1.c:1:10: error: expected identifier or ‘(’ before numeric constant 1.c: In function ‘m’: 1.c:1:9: warning: control reaches end of non-void function [-Wreturn-type]
Tento přístup změnil právě jazyk Elm a po něm i Rust či TypeScript (kupodivu Go v tomto ohledu poněkud zaostává). Naopak se poněkud zlepšila chybová hlášení céčkových překladačů, takže se předchozí chybová hlášení nyní zobrazují odlišně:
1.c:1:3: error: expected declaration specifiers or ‘...’ before ‘;’ token
1 | m(;){@,x}2
| ^
1.c:1:1: error: return type defaults to ‘int’ [-Wimplicit-int]
1 | m(;){@,x}2
| ^
1.c: In function ‘m’:
1.c:1:6: error: stray ‘@’ in program
1 | m(;){@,x}2
| ^
1.c:1:7: error: expected expression before ‘,’ token
1 | m(;){@,x}2
| ^
1.c:1:8: error: ‘x’ undeclared (first use in this function)
1 | m(;){@,x}2
| ^
1.c:1:8: note: each undeclared identifier is reported only once for each function it appears in
1.c:1:7: warning: left-hand operand of comma expression has no effect [-Wunused-value]
1 | m(;){@,x}2
| ^
1.c: At top level:
1.c:1:10: error: expected identifier or ‘(’ before numeric constant
1 | m(;){@,x}2
| ^
1.c: In function ‘m’:
1.c:1:9: warning: control reaches end of non-void function [-Wreturn-type]
1 | m(;){@,x}2
| ^
Ukažme si několik příkladů chybových hlášení získaných přímo z REPLu jazyka Elm:
---- Elm 0.19.1 ----------------------------------------------------------------
Say :help for help and :exit to exit! More at <https://elm-lang.org/0.19.1/repl>
--------------------------------------------------------------------------------
> 42
42 : number
> "foo"
"foo" : String
> 42+"foo"
-- TYPE MISMATCH ---------------------------------------------------------- REPL
I cannot do addition with String values like this one:
3| 42+"foo"
^^^^^
The (+) operator only works with Int and Float values.
Hint: Switch to the (++) operator to append strings!
> 42++"foo"
-- TYPE MISMATCH ---------------------------------------------------------- REPL
The (++) operator can append List and String values, but not number values like
this:
3| 42++"foo"
^^
Try using String.fromInt to turn it into a string? Or put it in [] to make it a
list? Or switch to the (::) operator?
> String.fromInt(42)++"foo"
"42foo" : String
Konečně jsme dospěli ke správné variantě :-)
> nil
-- NAMING ERROR ----------------------------------------------------------- REPL
I cannot find a `nil` variable:
3| nil
^^^
These names seem close though:
min
not
pi
sin
Hint: Read <https://elm-lang.org/0.19.1/imports> to see how `import`
declarations work in Elm.
Co může být lepšího, když chybové hlášení není jen „buzerací“ vývojáře (nepříjemné vzpomínky na Pascal), ale hlavně výukovým materiálem?:
> x=42 42 : number > x=x+1 -- CYCLIC DEFINITION ------------------------------------------------------ REPL The `x` value is defined directly in terms of itself, causing an infinite loop. 2| x=x+1 ^ Are you are trying to mutate a variable? Elm does not have mutation, so when I see x defined in terms of x, I treat it as a recursive definition. Try giving the new value a new name! Maybe you DO want a recursive value? To define x we need to know what x is, so let’s expand it. Wait, but now we need to know what x is, so let’s expand it... This will keep going infinitely! Hint: The root problem is often a typo in some variable name, but I recommend reading <https://elm-lang.org/0.19.1/bad-recursion> for more detailed advice, especially if you actually do need a recursive value.
Pokusme se překladač zmást – on to klidně přizná:
-- UNEXPECTED SYMBOL ------------------------------------------------------ REPL
I was not expecting to run into the "has type" symbol here:
3| 42: int
^
Maybe you want :: instead? To put something on the front of a list?
Note: The single colon is reserved for type annotations and record types, but I
think I am parsing the definition of `repl_input_value_` right now.
Note: I may be getting confused by your indentation. Is this supposed to be part
of a type annotation AFTER the `repl_input_value_` definition? If so, the
problem may be a bit before the "has type" symbol. I need all definitions to be
exactly aligned (with exactly the same indentation) so the problem may be that
this new definition is indented a bit too much.
Typový systém programovacího jazyka Elm
„Testing is good, impossible is better“
S některými datovými typy, které jsou jazykem Elm podporovány, jsme se (vlastně trošku mimochodem) setkali v předchozích kapitolách. Ovšem pro navazující články o Elm je nutné zmínit všechny podporované datové typy.
První datový typ se jmenuje unit, ovšem většinou se mu říká „null type“. Je reprezentován prázdnými kulatými závorkami a technicky se jedná o n-tici bez prvků:
> x=() () : ()
Dalším datovým typem je typ bool. Ten již není, na rozdíl od typu unit nijak výjimečný. Obsahuje dvě hodnoty true a false:
> a=True True : Bool > b=False False : Bool
Numerické datové typy jsou představovány obecnými čísly typu number, který se dále rozpadá na celá čísla Int a hodnoty s plovoucí řádovou čárkou Float (pozor: zde se Elm odlišuje od SML apod.):
> x = 42 42 : number > z = 1.5 1.5 : Float
Proměnnou typu Int je většinou nutné explicitně definovat. Povšimněte si, že určení typu proměnné a následné přiřazení je v REPLu zapsáno třemi příkazy:
> y : Int | y = 42 | 42 : Int
Některé operace ovšem dokážou produkovat přímo hodnotu typu Int – viz rozdíl mezi dvojicí operací podílu:
> 7/2 3.5 : Float > 7//2 3 : Int
Popř. též:
> round(7/2) 4 : Int
Protože typ funkce round vypadá takto:
> round <function> : Float -> Int
Následují řetězce, neboli typ string:
> msg="Hello world!" "Hello world!" : String
Řetězce mohou být i víceřádkové. Jejich zápis vypadá následovně:
> lorem_ipsum =
| """
| Lorem ipsum dolor sit amet, consectetur
| adipiscing elit, sed do eiusmod tempor
| incididunt ut labore et dolore magna
| aliqua. Ut enim ad minim veniam, quis
| nostrud exercitation ullamco laboris
| nisi ut aliquip ex ea commodo consequat.
| Duis aute irure dolor in reprehenderit
| in voluptate velit esse cillum dolore eu
| fugiat nulla pariatur. Excepteur sint
| occaecat cupidatat non proident, sunt in
| culpa qui officia deserunt mollit anim
| id est laborum.
| """
"\n Lorem ipsum dolor sit amet, consectetur\n adipiscing elit, sed do eiusmod
tempor\n incididunt ut labore et dolore magna\n aliqua. Ut enim ad minim
veniam, quis\n nostrud exercitation ullamco laboris\n nisi ut aliquip ex ea
commodo consequat.\n Duis aute irure dolor in reprehenderit\n in voluptate
velit esse cillum dolore eu\n fugiat nulla pariatur. Excepteur sint\n
occaecat cupidatat non proident, sunt in\n culpa qui officia deserunt mollit
anim\n id est laborum.\n "
: String
A konečně typ char reprezentujíje jediný znak:
> c='?' '?' : Char
Složené datové typy
V Elmu jsou podporovány tři složené datové typy: n-tice (Tuple), záznamy (Record) a seznamy (List). K nim se předávají ještě typy Maybe, Result, Dict a Set, které si popíšeme příště (společně s popisem záznamů).
Nejjednodušší jsou n-tice, které mohou obsahovat prvky libovolných typů. Typ n-tice jako celku je pak odvozen od typů jednotlivých prvků. Speciálním případem je n-tice bez prvků, neboli typ unit zmíněný v předchozí kapitole:
> x=() () : ()
Následuje příklad n-tic s větším množstvím prvků. Povšimněte si toho, jak je zapsán datový typ takové n-tice:
> (1, 2, 3)
(1,2,3) : ( number, number1, number2 )
> ("foo", "bar", "baz")
("foo","bar","baz") : ( String, String, String )
> ("answer", 42)
n-tice obsahující jiné n-tice:
> (1, (2, (3, 4)))
(1,(2,(3,4)))
: ( number, ( number1, ( number2, number3 ) ) )
Ovšem REPL z praktických důvodů neumožňuje konstrukci větších n-tic:
> (1, 2, 3, 4)
-- BAD TUPLE -------------------------------------------------------------- REPL
I only accept tuples with two or three items. This has too many:
5| (1, 2, 3, 4)
^^^^^^^^^^^^
I recommend switching to records. Each item will be named, and you can use the
`point.x` syntax to access them.
Note: Read <https://elm-lang.org/0.19.1/tuples> for more comprehensive advice on
working with large chunks of data in Elm.
Vzhledem k tomu, že n-tice s jediným prvkem nemá praktický význam, není podporována (na rozdíl od Pythonu, kde se však jedná o syntakticky problematický rys jazyka):
> (1)
1 : number
> (1,)
|
-- MISSING EXPRESSION ----------------------------------------------------- REPL
I am partway through parsing some parentheses, but I got stuck here:
5| (1,)
^
I was expecting to see an expression like 42 or "hello". Once there is something
there, I can probably give a more specific hint!
Note: This can also happen if run into reserved words like `let` or `as`
unexpectedly. Or if I run into operators in unexpected spots. Point is, there
are a couple ways I can get confused and give sort of weird advice!
A konečně, nejdůležitějším základním složeným datovým typem jsou seznamy (lists). Ty jsou homogenní, tj. všechny prvky seznamů musí být stejného typu:
> [1, 2, 3] [1,2,3] : List number
Pokus o vytvoření heterogenního seznamu skončí s chybou:
> [1, "foo", True]
-- TYPE MISMATCH ---------------------------------------------------------- REPL
The 2nd element of this list does not match all the previous elements:
5| [1, "foo", True]
^^^^^
The 2nd element is a string of type:
String
But all the previous elements in the list are:
number
Hint: Everything in a list must be the same type of value. This way, we never
run into unexpected values partway through a List.map, List.foldl, etc. Read
<https://elm-lang.org/0.19.1/custom-types> to learn how to “mix” types.
Hint: Try using String.toInt to convert it to an integer?
Víme již, že speciálním případem n-tice je n-tice bez prvků. I u seznamů se jedná o speciální případ, o čemž se můžeme velmi snadno přesvědčit (viz typ výrazu):
> [] [] : List a
Sémantika seznamů je ze značné míry převzata z LISPu, ovšem syntaxe práce s nimi je odlišná. Seznam může být v tomto kontextu definován rekurzivně:
- buď je seznam prázdný
- nebo má formu hlava::tělo, kde hlava je první prvek seznamu
Příklad:
> 1::[2,3] [1,2,3] : List number
To například znamená, že seznam [42] je shodný se seznamem 42::[]:
> [42] [42] : List number > 42::[] [42] : List number
Zápis hlava::tělo se používá jak pro konstrukci seznamu, tak i například ve vzorech (patterns), s nimiž se seznámíme později.
Standardní operátory, priorita a asociativita operátorů
V následující tabulce jsou vypsány všechny standardní operátory programovacího jazyka Elm. Tyto operátory se od sebe liší (pochopitelně) nejenom prováděnou operací, ale taktéž prioritou a asociativitou. Priorita určuje, v jakém pořadí se budou operátory vyhodnocovat, pokud jsou použity v jediném výrazu (například ve výrazu 1+2*3). A asociativita určuje uzávorkování operátorů se stejnou prioritou, tj. zda se provede (1+2)+3 nebo naopak 1+(2+3). Z tabulky je patrné, že některé operátory známé z jiných programovacích jazyků jsou asociativní zleva, ovšem skupina několika operátorů má asociativitu zprava:
| Operátor | Priorita | Asociativita | Stručný popis |
|---|---|---|---|
| >> | 9 | zleva | kompozice funkcí |
| << | 9 | zprava | kompozice funkcí |
| ^ | 8 | zprava | operace umocnění |
| * / // % rem | 7 | zleva | součin, podíl, zbytek po dělení |
| + – | 6 | zleva | součet a rozdíl |
| ++ :: | 5 | zprava | spojení řetězců a seznamů, přidání prvku do seznamu |
| == /= < > <= >= | 4 | × | relační operace |
| && | 3 | zprava | logická spojka „a“ |
| || | 2 | zprava | logická spojka „nebo“ |
| |> | 0 | zleva | operátor kolony (zřetězení volání funkcí) |
| <| | 0 | zprava | volání funkce, ovšem díky prioritě lze většinou vynechat závorky |
Poněkud sice předbíháme, ale už nyní si můžeme uvést, že standardní operátory jsou definovány následujícím způsobem (jsou tedy navázány na funkce, jejichž jména jsou uvedena v pravém sloupci):
infix right 0 (<|) = apL infix left 0 (|>) = apR infix right 2 (||) = or infix right 3 (&&) = and infix non 4 (==) = eq infix non 4 (/=) = neq infix non 4 (<) = lt infix non 4 (>) = gt infix non 4 (<=) = le infix non 4 (>=) = ge infix right 5 (++) = append infix left 6 (+) = add infix left 6 (-) = sub infix left 7 (*) = mul infix left 7 (/) = fdiv infix left 7 (//) = idiv infix right 8 (^) = pow infix left 9 (<<) = composeL infix right 9 (>>) = composeR
Definice funkcí a typová inference
Definice funkcí je zapsána poměrně přímočarým způsobem na jednom programovém řádku nebo na více řádcích (pochopitelně v závislosti na komplikovanosti těla funkce). V případě, že je funkce tvořena jediným výrazem, což je i případ funkce inc, lze ji zapsat na jeden řádek:
> inc x = x + 1 <function> : number -> number
Nic nám ovšem nebrání v zápisu funkce na více řádcích. Ukončení těla funkce v REPLu zajistí prázdný řádek (stisk Enteru):
> int x = | x+1 | <function> : number -> number
Povšimněte si, že díky typové inferenci byl korektně odvozen typ parametru funkce i typ návratové hodnoty. Ovšem taktéž je možné typ funkce určit explicitně. Poté se (opět v REPLu) nejprve zapíše hlavička funkce i se všemi typy (parametrů a návratové hodnoty) a na řádku dalším pak vlastní implementace funkce:
> inc : Int -> Int | inc x = x + 1 | <function> : Int -> Int
Dtto, ale pro funkci s tělem rozepsaným na samostatném řádku:
> inc : Int -> Int | inc x = | x + 1 | <function> : Int -> Int
Vlastní zavolání funkce je již triviální. Povšimněte si, že jsou prováděny i typové kontroly:
> inc 42
43 : Int
> inc 3.14
-- TYPE MISMATCH ---------------------------------------------------------- REPL
The 1st argument to `inc` is not what I expect:
7| inc 3.14
^^^^
This argument is a float of type:
Float
But `inc` needs the 1st argument to be:
Int
Note: Read <https://elm-lang.org/0.19.1/implicit-casts> to learn why Elm does
not implicitly convert Ints to Floats. Use toFloat and round to do explicit
conversions.
Funkce s větším počtem parametrů
Zajímavější bude zjistit, jak se definují a volají funkce s větším počtem parametrů. To si ostatně opět můžeme velmi snadno otestovat, a to například na funkci s realizací součtu. Jednořádková varianta založená na typové inferenci:
> add x y = x + y <function> : number -> number -> number > add 3 4 7 : number
Varianta zapsaná na více řádků:
> add x y = | x + y | <function> : number -> number -> number > add 3 4 7 : number
, což vlastně znamená „funkce akceptující číslo a vracející jinou funkci, která zobrazuje číslo na (jiné) číslo“. Tento způsob zápisu je v některých funkcionálních jazycích poměrně často používán a dá se na něj rychle zvyknout. A zápis typu se dá i ověřit:
> add 1 <function> : number -> number
Předáním jednoho parametru jsme skutečně získali funkci realizující zobrazení „číslo na číslo“.
Samozřejmě můžeme explicitně zapsat i typy parametrů funkce a typ návratové hodnoty. Musíme pouze dodržet stejný způsob zápisu „šipek“, jako je tomu u výsledku typové inference:
> add : Int -> Int -> Int | add x y = x + y | <function> : Int -> Int -> Int
Příklady typových definic standardních funkcí
Podívejme se na několik příkladů typových definic funkcí dostupných ve standardní knihovně programovacího jazyka Elm. Všechny definice prozkoumáme přímo z REPLu, čímž ověříme jak samotnou existenci funkce, tak i typ jejích parametrů i typ návratové hodnoty. Povšimněte si, jak popisná je dvojice jméno_funkce + typy; většinou ani není vyžadována další podrobnější dokumentace:
> abs <function> : number -> number > sqrt <function> : Float -> Float
Převody mezi typem Float a Int vyžadují nějakou formu manipulace s ciframi za desetinnou čárkou:
> floor <function> : Float -> Int > ceiling <function> : Float -> Int > round <function> : Float -> Int
Opačný převod je nutný kvůli silným typovým kontrolám:
> toFloat <function> : Int -> Float
Manipulace s řetězci, kde vstupem i výstupem je řetězec:
> String.toUpper <function> : String -> String > String.toLower <function> : String -> String > String.trim <function> : String -> String
Testy na obsah řetězce:
> String.startsWith <function> : String -> String -> Bool > String.endsWith <function> : String -> String -> Bool > String.contains <function> : String -> String -> Bool
Další funkce, jimiž prováděné operace by měly být zřejmé z uvedeného jména i typů:
> String.length <function> : String -> Int > String.concat <function> : List String -> String > String.split <function> : String -> String -> List String
Obsah navazujícího článku
V navazujícím článku o programovacím jazyku Elm se budeme věnovat dvěma důležitým tématům. Prvním z nich je využití strukturovaných datových typů, a to včetně práce s typem Result atd. A druhé téma se věnuje pattern matchingu, jenž je v Elmu používán ve spojitosti s různými datovými typy (v Elmu a dalších programovacích jazycích pocházejících z rodiny ML jsou tyto dvě vlastnosti jazyka úzce svázány, kdežto například v Pythonu tomu tak není).
Literatura
- Beginning Elm
https://elmprogramming.com/ - Elm in Action
https://www.manning.com/books/elm-in-action - Programming Language Fundamentals: A Metalanguage Approach in Elm
https://books.google.cz/books/about/Programming_Language_Fundamentals.html?id=ORH9EAAAQBAJ - Programming Elm: Build Safe and Maintainable Front-End Applications
https://www.goodreads.com/book/show/37824829-programming-elm - Web Applications with Elm: Functional Programming for the Web
https://www.goodreads.com/book/show/33160729-web-applications-with-elm - ML for the Working Programmer
https://www.cl.cam.ac.uk/~lp15/MLbook/pub-details.html - Elements of ML Programming, 2nd Edition (ML97)
http://infolab.stanford.edu/~ullman/emlp.html - A tour of Standard ML
https://saityi.github.io/sml-tour/tour/welcome - The History of Standard ML
https://smlfamily.github.io/history/SML-history.pdf - The Standard ML Basis Library
https://smlfamily.github.io/Basis/ - Programming in Standard ML
http://www.cs.cmu.edu/~rwh/isml/book.pdf - Programming in Standard ML '97: A Tutorial Introduction
http://www.lfcs.inf.ed.ac.uk/reports/97/ECS-LFCS-97–364/ - Programming in Standard ML '97: An On-line Tutorial
https://homepages.inf.ed.ac.uk/stg/NOTES/ - The OCaml system release 4.13
https://ocaml.org/releases/4.13/htmlman/index.html - Real World OCaml: Functional programming for the masses
https://dev.realworldocaml.org/ - OCaml from the Very Beginning
http://ocaml-book.com/ - OCaml from the Very Beginning: More OCaml : Algorithms, Methods & Diversions
http://ocaml-book.com/more-ocaml-algorithms-methods-diversions/ - Unix system programming in OCaml
http://ocaml.github.io/ocamlunix/ - OCaml for Scientists
https://www.ffconsultancy.com/products/ocaml_for_scientists/index.html - Using, Understanding, and Unraveling The OCaml Language
https://caml.inria.fr/pub/docs/u3-ocaml/ - Developing Applications With objective Caml
https://caml.inria.fr/pub/docs/oreilly-book/index.html - Introduction to Objective Caml
http://courses.cms.caltech.edu/cs134/cs134b/book.pdf - How to Think Like a (Functional) Programmer
https://greenteapress.com/thinkocaml/index.html - Types and Programming Languages
https://i.warosu.org/data/sci/img/0163/64/1725651701869705.pdf - Purely Functional Data Structures (Chris Okasaki)
https://www.cs.cmu.edu/~rwh/students/okasaki.pdf
Předchozí články o jazyku ML/SML i o jazycích OCaml a F#
- ML – funkcionální jazyk s revolučním typovým systémem
https://www.root.cz/clanky/ml-funkcionalni-jazyk-s-revolucnim-typovym-systemem/ - Funkce a typový systém programovacího jazyka ML
https://www.root.cz/clanky/funkce-a-typovy-system-programovaciho-jazyka-ml/ - Curryfikace (currying), výjimky a vlastní operátory v jazyku ML
https://www.root.cz/clanky/curryfikace-currying-vyjimky-a-vlastni-operatory-v-jazyku-ml/ - Funkcionální programovací jazyk F#
https://www.root.cz/clanky/funkcionalni-programovaci-jazyk-f/ - Programovací jazyk OCaml
https://www.root.cz/clanky/programovaci-jazyk-ocaml/ - Programovací jazyk F#: proměnné, funkce a datové typy
https://www.root.cz/clanky/programovaci-jazyk-f-promenne-funkce-a-datove-typy/ - Proměnné, funkce a datové typy v jazyku OCaml
https://www.root.cz/clanky/promenne-funkce-a-datove-typy-v-jazyku-ocaml/ - Rekurze a pattern matching v programovacím jazyku F#
https://www.root.cz/clanky/rekurze-a-pattern-matching-v-programovacim-jazyku-f/ - Práce se seznamy v jazyce F#
https://www.root.cz/clanky/prace-se-seznamy-v-jazyce-f/ - Programovací jazyk OCaml: rekurze, pattern matching a práce se seznamy
https://www.root.cz/clanky/programovaci-jazyk-ocaml-rekurze-pattern-matching-a-prace-se-seznamy/ - Datové typy Option, Result a Array v programovacím jazyku F#
https://www.root.cz/clanky/datove-typy-option-result-a-array-v-programovacim-jazyku-f/ - Datové typy Option, Result a Array v programovacím jazyku OCaml
https://www.root.cz/clanky/datove-typy-option-result-a-array-v-programovacim-jazyku-ocaml/ - Operátory v programovacím jazyku OCaml
https://www.root.cz/clanky/operatory-v-programovacim-jazyku-ocaml/ - Operátory v programovacím jazyku F#
https://www.root.cz/clanky/operatory-v-programovacim-jazyku-f/ - Definice uživatelských datových typů v jazyku F#
https://www.root.cz/clanky/definice-uzivatelskych-datovych-typu-v-jazyku-f/ - Definice uživatelských datových typů v jazyku OCaml
https://www.root.cz/clanky/definice-uzivatelskych-datovych-typu-v-jazyku-ocaml/ - Rekurzivní datové typy v jazyku OCaml
https://www.root.cz/clanky/rekurzivni-datove-typy-v-jazyku-ocaml/ - Řídicí konstrukce v programovacím jazyku OCaml
https://www.root.cz/clanky/ridici-konstrukce-v-programovacim-jazyku-ocaml/ - LunarML: až překvapivě kvalitní transpiler z jazyka Standard ML do jazyků Lua a JavaScript
https://www.root.cz/clanky/lunarml-az-prekvapive-kvalitni-transpiler-z-jazyka-standard-ml-do-jazyku-lua-a-javascript/ - LunarML: definice a volání různých variant funkcí
https://www.root.cz/clanky/lunarml-definice-a-volani-ruznych-variant-funkci/ - LunarML: definice vlastních operátorů a pokročilý typový systém jazyka
https://www.root.cz/clanky/lunarml-definice-vlastnich-operatoru-a-pokrocily-typovy-system/
Odkazy na Internetu
- Elm in 2026: The Language That Stopped Changing — And What That Actually Means
https://medium.com/@reactjsbd/elm-in-2026-the-language-that-stopped-changing-and-what-that-actually-means-2b08c598528a - The Syntax Cliff: Teaching syntax with Elm 0.19.1
https://elm-lang.org/news/the-syntax-cliff - Stránky projektu Elm
https://elm-lang.org/ - Binární balíčky s jazykem Elm
https://github.com/elm/compiler/releases - Pískoviště pro jazyk Elm
https://elm-lang.org/try - LunarML documentation
https://lunarml.readthedocs.io/en/latest/index.html - Standard ML of New Jersey
https://www.smlnj.org/ - Programming Languages: Standard ML – 1 (a navazující videa)
https://www.youtube.com/watch?v=2sqjUWGGzTo - 6 Excellent Free Books to Learn Standard ML
https://www.linuxlinks.com/excellent-free-books-learn-standard-ml/ - SOSML: The Online Interpreter for Standard ML
https://sosml.org/ - ML (Computer program language)
https://www.barnesandnoble.com/b/books/other-programming-languages/ml-computer-program-language/_/N-29Z8q8Zvy7 - Strong Typing
https://perl.plover.com/yak/typing/notes.html - What to know before debating type systems
http://blogs.perl.org/users/ovid/2010/08/what-to-know-before-debating-type-systems.html - Types, and Why You Should Care (Youtube)
https://www.youtube.com/watch?v=0arFPIQatCU - DynamicTyping (Martin Fowler)
https://www.martinfowler.com/bliki/DynamicTyping.html - DomainSpecificLanguage (Martin Fowler)
https://www.martinfowler.com/bliki/DomainSpecificLanguage.html - Language Workbenches: The Killer-App for Domain Specific Languages?
https://www.martinfowler.com/articles/languageWorkbench.html - Effective ML (Youtube)
https://www.youtube.com/watch?v=-J8YyfrSwTk - Why OCaml (Youtube)
https://www.youtube.com/watch?v=v1CmGbOGb2I - CSE 341: Functions and patterns
https://courses.cs.washington.edu/courses/cse341/04wi/lectures/03-ml-functions.html - Comparing Objective Caml and Standard ML
http://adam.chlipala.net/mlcomp/ - What are the key differences between Standard ML and OCaml?
https://www.quora.com/What-are-the-key-differences-between-Standard-ML-and-OCaml?share=1 - Cheat Sheets (pro OCaml)
https://www.ocaml.org/docs/cheat_sheets.html - Syllabus (FAS CS51)
https://cs51.io/college/syllabus/ - Abstraction and Design In Computation
http://book.cs51.io/ - Learn X in Y minutes Where X=Standard ML
https://learnxinyminutes.com/docs/standard-ml/ - CSE307 Online – Summer 2018: Principles of Programing Languages course
https://www3.cs.stonybrook.edu/~pfodor/courses/summer/cse307.html - CSE307 Principles of Programming Languages course: SML part 1
https://www.youtube.com/watch?v=p1n0_PsM6hw - CSE 307 – Principles of Programming Languages – SML
https://www3.cs.stonybrook.edu/~pfodor/courses/summer/CSE307/L01_SML.pdf - SML, Some Basic Examples
https://cs.fit.edu/~ryan/sml/intro.html - History of programming languages
https://devskiller.com/history-of-programming-languages/ - History of programming languages (Wikipedia)
https://en.wikipedia.org/wiki/History_of_programming_languages - Jemný úvod do rozsáhlého světa jazyků LISP a Scheme
https://www.root.cz/clanky/jemny-uvod-do-rozsahleho-sveta-jazyku-lisp-a-scheme/ - The Evolution Of Programming Languages
https://www.i-programmer.info/news/98-languages/8809-the-evolution-of-programming-languages.html - Evoluce programovacích jazyků
https://ccrma.stanford.edu/courses/250a-fall-2005/docs/ComputerLanguagesChart.png - Poly/ML Homepage
https://polyml.org/ - PolyConf 16: A brief history of F# / Rachel Reese
https://www.youtube.com/watch?v=cbDjpi727aY - Programovací jazyk Clojure 18: základní techniky optimalizace aplikací
https://www.root.cz/clanky/programovaci-jazyk-clojure-18-zakladni-techniky-optimalizace-aplikaci/ - Moscow ML Language Overview
https://itu.dk/people/sestoft/mosml/mosmlref.pdf - ForLoops
http://mlton.org/ForLoops - Funkcionální dobrodružství v JavaScriptu
https://blog.kolman.cz/2015/12/funkcionalni-dobrodruzstvi-v-javascriptu.html - Recenze knihy Functional Thinking (Paradigm over syntax)
https://www.root.cz/clanky/recenze-knihy-functional-thinking-paradigm-over-syntax/ - Currying
https://sw-samuraj.cz/2011/02/currying/ - Používání funkcí v F#
https://docs.microsoft.com/cs-cz/dotnet/fsharp/tutorials/using-functions - Funkce vyššího řádu
http://naucte-se.haskell.cz/funkce-vyssiho-radu - Currying (Wikipedia)
https://en.wikipedia.org/wiki/Currying - Currying (Haskell wiki)
https://wiki.haskell.org/Currying - Haskell Curry
https://en.wikipedia.org/wiki/Haskell_Curry - Moses Schönfinkel
https://en.wikipedia.org/wiki/Moses_Sch%C3%B6nfinkel - Fibonacci sequence
https://en.wikipedia.org/wiki/Fibonacci_sequence - Moonscript: jazyk inspirovaný CoffeeScriptem určený pro ekosystém jazyka Lua
https://www.root.cz/clanky/moonscript-jazyk-inspirovany-coffeescriptem-urceny-pro-ekosystem-jazyka-lua/ - Moonscript: jazyk inspirovaný CoffeeScriptem určený pro ekosystém jazyka Lua (2)
https://www.root.cz/clanky/moonscript-jazyk-inspirovany-coffeescriptem-urceny-pro-ekosystem-jazyka-lua-2/ - Moonscript: jazyk inspirovaný CoffeeScriptem určený pro ekosystém jazyka Lua (dokončení)
https://www.root.cz/clanky/moonscript-jazyk-inspirovany-coffeescriptem-urceny-pro-ekosystem-jazyka-lua-dokonceni/ - Programovací jazyk Lua v roli skriptovacího jazyka pro WWW stránky
https://www.root.cz/clanky/programovaci-jazyk-lua-v-roli-skriptovaciho-jazyka-pro-www-stranky/ - Transcrypt: technologie umožňující použití Pythonu v prohlížeči
https://www.root.cz/clanky/transcrypt-technologie-umoznujici-pouziti-pythonu-v-prohlizeci/ - GopherJS: transpřekladač z jazyka Go do JavaScriptu
https://www.root.cz/clanky/gopherjs-transprekladac-z-jazyka-go-do-javascriptu/ - Rychlost CPythonu 3.11 a 3.12 v porovnání s JIT a AOT překladači
https://www.root.cz/clanky/rychlost-cpythonu-3–11-a-3–12-v-porovnani-s-jit-a-aot-prekladaci-pythonu/ - Seriál F# a OCaml
https://www.root.cz/serialy/f-a-ocaml/ - Haskell or Standard ML for beginners?
https://stackoverflow.com/questions/810409/haskell-or-standard-ml-for-beginners#813646 - Awesome transpilers
https://github.com/milahu/awesome-transpilers - Languages that compile to JS (from CoffeeScript wiki)
https://gist.github.com/matthiasak/c3c9c40d0f98ca91def1 - Common Language Runtime
https://en.wikipedia.org/wiki/Common_Language_Runtime - 7 Old Programming Languages Developers Still Won’t Quit
https://medium.com/javarevisited/7-old-programming-languages-developers-still-wont-quit-42f8136ef678 - Lambdera: A delightful platform for full-stack web apps
https://www.lamdera.com/ - Mario Rogic – Elm as a Service
https://www.youtube.com/watch?v=nSrucNcwlA8 - Developer Happiness on the Front End with Elm
https://www.youtube.com/watch?v=kuOCx0QeQ5c - Elm & The Future of Open Source (with Evan Czaplicki)
https://www.youtube.com/watch?v=0SUM4869ODc - Package Managers Need to Cool Down
https://nesbitt.io/2026/03/04/package-managers-need-to-cool-down.html - Fable
https://fable.io/ - „Making Impossible States Impossible“ by Richard Feldman
https://www.youtube.com/watch?v=IcgmSRJHu8 - Error Messages: The Art of Effective Communication in Software Development
https://dev.to/favourmark05/writing-proper-error-messages-the-art-of-effective-communication-in-software-development-emj
