Hlavní navigace

Pattern matching v programovacím jazyku Coconut

25. 6. 2024
Doba čtení: 40 minut

Sdílet

 Autor: Depositphotos
S technologií pattern matchingu resp. vylepšenou formou strukturální pattern matching jsme se zde již setkali. V jazyku Coconut je strukturální pattern matching všudypřítomným prvkem a je „mocnější“, než v Pythonu.

Obsah

1. Pattern matching v programovacím jazyku Coconut

2. Výpočet faktoriálu řešený pattern matchingem: původní syntaxe Coconutu

3. Výsledek transpřekladu do Pythonu: od pattern matchingu k bludišti plném if-ů

4. Přepis do syntaxe Coconutu kompatibilní s Pythonem 3.10

5. Chování algoritmu pro výpočet faktoriálu při zadání záporných hodnot

6. Oprava skriptu: přidání kontroly hodnoty předané do funkce pro výpočet faktoriálu

7. Test na typ hodnoty jako součást vzorku (pattern)

8. Způsob transpřekladu větví s testem typů hodnoty

9. Nový způsob zápisu testu na typ hodnoty

10. Spojení několika variant vzorků do vzorku jediného

11. Strukturální pattern matching

12. Zjištění počtu prvků v seznamu

13. Výpis počtu prvků seznamu i jejich hodnot

14. Chování skriptu ve chvíli, kdy funkci není předán seznam

15. Kontrola, zda je předán seznam

16. Realizace komplexních čísel s využitím n-tice s reálnou a imaginární hodnotou

17. Test, zda je reálná a/nebo imaginární složka komplexního čísla reprezentovaná numerickou hodnotou

18. Další možnosti poskytované programovacím jazykem Coconut v oblasti pattern matchingu

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

20. Odkazy na Internetu

1. Pattern matching v programovacím jazyku Coconut

S technologií pattern matchingu resp. s jeho vylepšenou formou nazývanou strukturální pattern matching jsme se již na stránkách Roota setkali, a to několikrát a dokonce i v souvislosti s několika různými programovacími jazyky (SNOBOL, Rust, ML, OCaml, F#, Clojure a nakonec i Python). Ovšem není divu, protože se jedná o velmi užitečnou technologii, která má za sebou dlouhý vývoj, ovšem teprve v posledních několika letech se postupně dostává i do mainstreamových programovacích jazyků (kam se postupně přidávají i další technologie, například podpora pro proudové zpracování dat nebo pro asynchronní programování).

Na pattern matching se můžeme dívat dvěma způsoby. Na první pohled většinou vzdáleně připomíná konstrukci switch-case z jazyka C (odkud byla převzata do dalších programovacích jazyků, včetně C++ či Javy). Ve skutečnosti jsou ovšem možnosti nabízené strukturálním pattern matchingem mnohem větší, což si ostatně ukážeme na demonstračních příkladech použitých v navazujících kapitolách.

Pattern matching tvoří nedílnou součást programovacího jazyka Coconut a dokonce by bylo možné říci, že je to centrální prvek tohoto jazyka (i když například kolony či vlastní infixové operátory atd. jsou možná více viditelné), podobně, jako je tomu u jazyků ve větvi ML (Standard ML, CAML, OCaml a F#). Ale vzhledem k tomu, že se Coconut překládá do jazyka Python, může si čtenář dnešního článku položit otázku, co vlastně Coconut nabízí nového či vylepšeného oproti Pythonu, protože i do programovacího jazyka Python, konkrétně do Pythonu 3.10, byla podpora pro pattern matching přidána. Některé dále uvedené demonstrační příklady budou skutečně odpovídat Pythonu, ovšem i přesto uvidíme, že strukturální pattern matching v Coconutu je v některých ohledech (dokonce v mnoha ohledech) obecnější, než je tomu v současném Pythonu. To může znamenat, že Coconut Pythonu razí cestu a možná se v některých dalších verzích Pythonu setkáme s „coconutovskými“ konstrukcemi a vzory (patterny).

2. Výpočet faktoriálu řešený pattern matchingem: původní syntaxe Coconutu

Jak jsme si již řekli v úvodní kapitole, můžeme se na pattern matching dívat jako na vylepšenou konstrukci switch-case, což je sice poměrně úzký pohled, na druhou stranu nám však umožní snadný vstup do světa pattern matchingu. Pokusme se tedy zapsat klasický rekurzivní algoritmus pro výpočet faktoriálu právě s využitím pattern matchingu. Nejprve si uvedeme variantu zapsanou v syntaxi původního jazyka Coconut, která je stále podporována. Co je na tomto zápisu zvláštní a specifické – pattern matching v Coconutu o několik let předešel Python a proto je zvolená role klíčových slov case a match oproti Pythonu prohozená. Dnes je tento způsob zápisu v Coconutu sice stále podporován, ale je považován za zastaralý:

def factorial_variant_A(n):
    case n:
        match 0:
            return 1
        match 1:
            return 1
        match x:
            return x * factorial_variant_A(x-1)
 
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_A(n)))
Poznámka: povšimněte si, že za match nemusí být uvedena konstanta, ale vzor může být realizován i složitější konstrukcí (nejedná se o „pouhý“ výraz, i když to tak na první pohled vypadá).

Zkusme si tento program spustit:

0!=1
1!=1
2!=2
3!=6
4!=24
5!=120
6!=720
7!=5040
8!=40320
9!=362880
10!=3628800

3. Výsledek transpřekladu do Pythonu: od pattern matchingu k bludišti plném if-ů

Pro zajímavost se podívejme na to, jakým způsobem je vlastně proveden překlad výše uvedeného skriptu do jazyka Python. Coconut v tomto případě použije konstrukce if/else a nikoli „nativní“ pythonní pattern matching (který by pro složitější konstrukce stejně nebylo možné použít):

# Compiled Coconut: -----------------------------------------------------------
 
def factorial_variant_A(n):  #1 (line in Coconut source)
    _coconut_case_match_to_0 = n  #2 (line in Coconut source)
    _coconut_case_match_check_0 = False  #2 (line in Coconut source)
    if _coconut_case_match_to_0 == 0:  #2 (line in Coconut source)
        _coconut_case_match_check_0 = True  #2 (line in Coconut source)
    if _coconut_case_match_check_0:  #2 (line in Coconut source)
        return 1  #4 (line in Coconut source)
    if not _coconut_case_match_check_0:  #5 (line in Coconut source)
        if _coconut_case_match_to_0 == 1:  #5 (line in Coconut source)
            _coconut_case_match_check_0 = True  #5 (line in Coconut source)
        if _coconut_case_match_check_0:  #5 (line in Coconut source)
            return 1  #6 (line in Coconut source)
    if not _coconut_case_match_check_0:  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_sentinel  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_case_match_to_0  #7 (line in Coconut source)
        _coconut_case_match_check_0 = True  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            if _coconut_match_set_name_x is not _coconut_sentinel:  #7 (line in Coconut source)
                x = _coconut_match_set_name_x  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            return x * factorial_variant_A(x - 1)  #8 (line in Coconut source)
 
 
 
for n in range(11):  #11 (line in Coconut source)
    print("{n}!={f}".format(n=n, f=factorial_variant_A(n)))  #12 (line in Coconut source)

4. Přepis do syntaxe Coconutu kompatibilní s Pythonem 3.10

Jak v Pythonu (od verze 3.10), tak i v nových verzích jazyka Coconut je však role klíčových slov match a case odlišná – slovo match zahajuje celý blok se vzory a je za ním zapsán výraz, který se vyhodnotí. A jednotlivá slova case představují začátky jednotlivých vzorků (patterns). Z tohoto důvodu si předchozí příklad přepíšeme do podoby kompatibilní jak s Pythonem 3.10, tak i s novými verzemi Coconutu. Všechny další příklady uvedené v dnešním článku již budou zapsány tímto způsobem:

def factorial_variant_A(n):
    match n:
        case 0:
            return 1
        case 1:
            return 1
        case x:
            return x * factorial_variant_A(x-1)
 
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_A(n)))

Zajímavé je, že tento skript je přeložen do naprosto stejného Pythonovského kódu (do posledního znaku totožného), jako tomu bylo u příkladu prvního:

# Compiled Coconut: -----------------------------------------------------------
 
def factorial_variant_A(n):  #1 (line in Coconut source)
    _coconut_case_match_to_0 = n  #2 (line in Coconut source)
    _coconut_case_match_check_0 = False  #2 (line in Coconut source)
    if _coconut_case_match_to_0 == 0:  #2 (line in Coconut source)
        _coconut_case_match_check_0 = True  #2 (line in Coconut source)
    if _coconut_case_match_check_0:  #2 (line in Coconut source)
        return 1  #4 (line in Coconut source)
    if not _coconut_case_match_check_0:  #5 (line in Coconut source)
        if _coconut_case_match_to_0 == 1:  #5 (line in Coconut source)
            _coconut_case_match_check_0 = True  #5 (line in Coconut source)
        if _coconut_case_match_check_0:  #5 (line in Coconut source)
            return 1  #6 (line in Coconut source)
    if not _coconut_case_match_check_0:  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_sentinel  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_case_match_to_0  #7 (line in Coconut source)
        _coconut_case_match_check_0 = True  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            if _coconut_match_set_name_x is not _coconut_sentinel:  #7 (line in Coconut source)
                x = _coconut_match_set_name_x  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            return x * factorial_variant_A(x - 1)  #8 (line in Coconut source)
 
 
 
for n in range(11):  #11 (line in Coconut source)
    print("{n}!={f}".format(n=n, f=factorial_variant_A(n)))  #12 (line in Coconut source)

5. Chování algoritmu pro výpočet faktoriálu při zadání záporných hodnot

Ve skutečnosti není výpočet faktoriálu realizovaný v obou předchozích skriptech zcela korektní, protože se nekontrolují vstupní hodnoty n na nepodporovaný vstup (definiční obor funkce faktoriál). To si ostatně můžeme snadno ověřit, a to konkrétně tak, že se pokusíme o výpočet faktoriálu z hodnoty n=-1, tedy ze záporného čísla. Test na záporná čísla není v algoritmu realizován a proto dojde k nekonečné rekurzi, která ovšem pochopitelně skončí po zaplnění zásobníku:

Traceback (most recent call last):
  File "<frozen runpy>", line 291, in run_path
  File "<frozen runpy>", line 98, in _run_module_code
  File "<frozen runpy>", line 88, in _run_code
  File "/home/ptisnovs/xy/pattern-matching-1.py", line 2927, in <module>
    print(factorial_variant_A(-1))  #14 (line in Coconut source)
          ^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ptisnovs/xy/pattern-matching-1.py", line 2920, in factorial_variant_A
    return x * factorial_variant_A(x - 1)  #8 (line in Coconut source)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ptisnovs/xy/pattern-matching-1.py", line 2920, in factorial_variant_A
    return x * factorial_variant_A(x - 1)  #8 (line in Coconut source)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ptisnovs/xy/pattern-matching-1.py", line 2920, in factorial_variant_A
    return x * factorial_variant_A(x - 1)  #8 (line in Coconut source)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  [Previous line repeated 1898 more times]
RecursionError: maximum recursion depth exceeded
Poznámka: to tedy programátora (tedy v tomto případě autora článku) neukazuje v příliš dobrém světle :-)

6. Oprava skriptu: přidání kontroly hodnoty předané do funkce pro výpočet faktoriálu

Opravu můžeme realizovat hned několika možnými způsoby. Jeden z těchto způsobů spočívá v tom, že třetí větev se vzorkem „libovolné číslo“ změníme na vzorek „hodnota větší než 1“. Ve vzorku je totiž možné použít i doplňující podmínku. A navíc doplníme i větev else, která je provedena ve chvíli, kdy vstupní hodnota neodpovídá ani jednomu vzorku, tedy ani jedné větvi case:

def factorial_variant_B(n):
    match n:
        case 0:
            return 1
        case 1:
            return 1
        case x if x > 1:
            return x * factorial_variant_B(x-1)
    else:
        raise TypeError("expecting integer >= 0")
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_B(n)))
Poznámka: větev else v bloku match je specialita jazyka Coconut a v Pythonu ji nenalezneme.

Překlad do programovacího jazyka Python je prozatím stále velmi krátký, takže si ho uvedeme (u složitějších příkladů však už tuto část vynecháme s ohledem na délku článku):

# Compiled Coconut: -----------------------------------------------------------
 
def factorial_variant_B(n):  #1 (line in Coconut source)
    _coconut_case_match_to_0 = n  #2 (line in Coconut source)
    _coconut_case_match_check_0 = False  #2 (line in Coconut source)
    if _coconut_case_match_to_0 == 0:  #2 (line in Coconut source)
        _coconut_case_match_check_0 = True  #2 (line in Coconut source)
    if _coconut_case_match_check_0:  #2 (line in Coconut source)
        return 1  #4 (line in Coconut source)
    if not _coconut_case_match_check_0:  #5 (line in Coconut source)
        if _coconut_case_match_to_0 == 1:  #5 (line in Coconut source)
            _coconut_case_match_check_0 = True  #5 (line in Coconut source)
        if _coconut_case_match_check_0:  #5 (line in Coconut source)
            return 1  #6 (line in Coconut source)
    if not _coconut_case_match_check_0:  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_sentinel  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_case_match_to_0  #7 (line in Coconut source)
        _coconut_case_match_check_0 = True  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            if _coconut_match_set_name_x is not _coconut_sentinel:  #7 (line in Coconut source)
                x = _coconut_match_set_name_x  #7 (line in Coconut source)
        if _coconut_case_match_check_0 and not (x > 1):  #7 (line in Coconut source)
            _coconut_case_match_check_0 = False  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            return x * factorial_variant_B(x - 1)  #8 (line in Coconut source)
    if not _coconut_case_match_check_0:  #9 (line in Coconut source)
        raise TypeError("expecting integer >= 0")  #10 (line in Coconut source)
 
 
for n in range(11):  #12 (line in Coconut source)
    print("{n}!={f}".format(n=n, f=factorial_variant_B(n)))  #13 (line in Coconut source)

7. Test na typ hodnoty jako součást vzorku (pattern)

Co se stane ve chvíli, kdy do funkce pro výpočet faktoriálu nepředáme celé kladné číslo? To si lze snadno otestovat:

def factorial_variant_B(n):
    match n:
        case 0:
            return 1
        case 1:
            return 1
        case x if x > 1:
            return x * factorial_variant_B(x-1)
    else:
        raise TypeError("expecting integer >= 0")
 
print(factorial_variant_B("foo"))

Pokus o spuštění podle očekávání dopadne neslavně:

Compiling         pattern-matching-3-error.coco ...
Compiled to       pattern-matching-3-error.py .
Traceback (most recent call last):
  File "<frozen runpy>", line 291, in run_path
  File "<frozen runpy>", line 98, in _run_module_code
  File "<frozen runpy>", line 88, in _run_code
  File "/home/ptisnovs/src/most-popular-python-libs/coconut/pattern-matching-3-error.py", line 2927, in <module>
    print(factorial_variant_B("foo"))  #12 (line in Coconut source)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ptisnovs/src/most-popular-python-libs/coconut/pattern-matching-3-error.py", line 2919, in factorial_variant_B
    if _coconut_case_match_check_0 and not (x > 1):  #7 (line in Coconut source)
                                            ^^^^^
TypeError: '>' not supported between instances of 'str' and 'int'

Ve vzorku může být zapsán i test na typ hodnoty. Opět se zde můžeme setkat s dvojí syntaxí (a stejnou sémantikou). První syntaxe zápisu typu vypadá takto:

case ... <expression> is <type>

Jedná se o způsob zápisu, který byl navržen a implementován v prvních verzích programovacího jazyka Coconut a je stále podporován. Doplňme si tedy náš algoritmus pro výpočet faktoriálu o test, zda do funkce bylo předáno celé číslo a nikoli například None, řetězec či nějaký objekt jiného typu. Tento test můžeme provést až u třetí větve, protože první dvě větve testují rovnost s celočíselnou konstantou (což ve skutečnosti není zcela pravda kvůli automatickému převodu hodnot typu float, které za desetinnou tečkou obsahují jen nuly):

def factorial_variant_C(n):
    match n:
        case 0:
            return 1
        case 1:
            return 1
        case x is int if x > 1:
            return x * factorial_variant_C(x-1)
    else:
        raise TypeError("expecting integer >= 0")
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_C(n)))

8. Způsob transpřekladu větví s testem typů hodnoty

Povšimněte si, že se v kódu přeloženém do Pythonu používá test na typ založený na volání isinstance, což dobře odpovídá Pythonu a jeho hierarchii datových typů:

# Compiled Coconut: -----------------------------------------------------------
 
def factorial_variant_C(n):  #1 (line in Coconut source)
    _coconut_case_match_to_0 = n  #2 (line in Coconut source)
    _coconut_case_match_check_0 = False  #2 (line in Coconut source)
    if _coconut_case_match_to_0 == 0:  #2 (line in Coconut source)
        _coconut_case_match_check_0 = True  #2 (line in Coconut source)
    if _coconut_case_match_check_0:  #2 (line in Coconut source)
        return 1  #4 (line in Coconut source)
    if not _coconut_case_match_check_0:  #5 (line in Coconut source)
        if _coconut_case_match_to_0 == 1:  #5 (line in Coconut source)
            _coconut_case_match_check_0 = True  #5 (line in Coconut source)
        if _coconut_case_match_check_0:  #5 (line in Coconut source)
            return 1  #6 (line in Coconut source)
    if not _coconut_case_match_check_0:  #7 (line in Coconut source)
        _coconut_match_set_name_x = _coconut_sentinel  #7 (line in Coconut source)
        if _coconut.isinstance(_coconut_case_match_to_0, int):  #7 (line in Coconut source)
            _coconut_match_set_name_x = _coconut_case_match_to_0  #7 (line in Coconut source)
            _coconut_case_match_check_0 = True  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            if _coconut_match_set_name_x is not _coconut_sentinel:  #7 (line in Coconut source)
                x = _coconut_match_set_name_x  #7 (line in Coconut source)
        if _coconut_case_match_check_0 and not (x > 1):  #7 (line in Coconut source)
            _coconut_case_match_check_0 = False  #7 (line in Coconut source)
        if _coconut_case_match_check_0:  #7 (line in Coconut source)
            return x * factorial_variant_C(x - 1)  #8 (line in Coconut source)
    if not _coconut_case_match_check_0:  #9 (line in Coconut source)
        raise TypeError("expecting integer >= 0")  #10 (line in Coconut source)
 
 
for n in range(11):  #12 (line in Coconut source)
    print("{n}!={f}".format(n=n, f=factorial_variant_C(n)))  #13 (line in Coconut source)

9. Nový způsob zápisu testu na typ hodnoty

Ve skutečnosti je výše uvedený způsob zápisu testu typu:

case ... <expression> is <type> ...

považován za zastaralý (i když mi připadne velmi čitelný). Namísto toho se dnes doporučuje používat zápis, který je do určité míry kompatibilní i s Pythonem (i když Python má omezenější možnosti):

case ... <type>(expression) ...

Zkusme si tedy ještě jednou upravit funkci pro výpočet faktoriálu, tentokrát do podoby s „kompatibilním“ testem na typ výrazu:

def factorial_variant_C(n):
    match n:
        case 0:
            return 1
        case 1:
            return 1
        case int(x) if x > 1:
            return x * factorial_variant_C(x-1)
    else:
        raise TypeError("expecting integer >= 0")
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_C(n)))

10. Spojení několika variant vzorků do vzorku jediného

Ve všech předchozích zápisech algoritmu pro výpočet faktoriálu se pro vstupní hodnoty n=0n=1 vrací stejný výsledek 1. Bylo by tedy vhodné nějakým způsobem zajistit jednodušší a kratší způsob zápisu vzorků, které (i když jsou různé) budou mít stejný vliv na výpočet. Toho lze ve skutečnosti dosáhnout velmi snadno, a to použitím operátoru |. Opět je dobré si uvědomit, že vzorek není klasickým výrazem, protože se hodnota 0 | 1 nevyhodnotí (což by vedlo k výsledku 1, tedy vzorek by už neprováděl test na nulu), ale celý zápis se považuje za dva vzorky, z nichž alespoň jeden musí být splněn, aby se provedla příslušná větev:

def factorial_variant_C(n):
    match n:
        case 0 | 1:
            return 1
        case int(x) if x > 1:
            return x * factorial_variant_C(x-1)
    else:
        raise TypeError("expecting integer >= 0")
 
for n in range(11):
    print("{n}!={f}".format(n=n, f=factorial_variant_C(n)))

11. Strukturální pattern matching

Prozatím jsme si vlastně popisovali jednoduchý pattern matching, konkrétně (zjednodušeně řečeno) určitou formu konstrukce switch-case nebo sekvenci bloků if-elif-elif-…-else, ale zapsanou odlišným způsobem. Ovšem jak programovací jazyk Coconut, tak i do jisté míry jazyk Python podporují strukturální pattern matching, který je sofistikovanější a v mnoha ohledech i mocnější.

Strukturální pattern matching totiž umožňuje porovnat vzorek s nějakou strukturovanou hodnotou (tedy datovou strukturou), kterou může být seznam, n-tice, množina, slovník, multimnožina atd. Ovšem takovou hodnotou navíc může být i instance nějaké třídy (tedy například objekt typu Zakaznik apod.). Navíc vzorek nemusí obsahovat pouze konstantní výrazy (což jsme ostatně viděli u větve case x), ale i zástupné symboly (placeholdery), které jsou v případě, že data odpovídají vzorku, naplněny hodnotami z těchto dat a bude je možné využít v příslušné větvi case.

12. Zjištění počtu prvků v seznamu

Výše uvedený popis je prozatím hodně teoretický a je možná složité si pod ním představit konkrétní vzorky nebo konkrétní využití pattern matchingu. Ukažme si tedy velmi jednoduchý (a nutno říci, že prozatím i dosti umělý) demonstrační příklad, ve kterém budeme zjišťovat, kolik prvků obsahuje předaný seznam. Výsledkem má být jeden z těchto řetězců:

  • „empty list“
  • „list, one item“
  • „list, two items“
  • „list with more than two items“

Tento problém můžeme vyřešit například tak, že si vypočteme délku seznamu a posléze budeme pattern matching provádět vůči hodnotám 0, 1, 2 a taktéž vůči vzorku len>2. Ale také lze postupovat jinak, a to právě s přímým využitím vzorků, které obsahují informaci, jakou strukturu má mít původní seznam. Toto řešení je sice složitější, ale jak uvidíme dále, umožní nám příklad dále rozšiřovat o další vlastnosti. V příkladu jsou tedy tyto vzorky:

  • seznam s libovolnými dvěma prvky a a b
  • seznam s s jediným prvkem a
  • prázdný seznam
  • vzorek _ odpovídající jakékoli hodnotě (předpokládáme, že se jedná o seznam)

Na pořadí prvních tří vzorků v tomto případě nezáleží, neboť se vzájemně vylučují:

def list_type(x):
    match x:
        case [a, b]:
            return "list, two items"
        case [a]:
            return "list, one item"
        case []:
            return "empty list"
        case _:
            return "list with more than two items"
 
 
print(list_type([]))
print(list_type([1]))
print(list_type([1, 2]))
print(list_type([1, 2, 3]))

13. Výpis počtu prvků seznamu i jejich hodnot

Předchozí skript používal strukturální pattern matching proto, že další rozšiřování možností tohoto skriptu bude relativně snadné, určitě snadnější, než kdyby se nejprve spočítala délka seznamu a později se pracovalo jen s touto hodnotou. Můžeme například chtít, aby se nevypsal pouze počet prvků seznamu (slovy „one“, „two“ atd.), ale i hodnoty onoho jediného prvku či dvojice prvků. Využijeme přitom toho, že ve vzorcích jsou prvky pojmenovány zástupnými symboly (placeholdery) a a b, jejichž hodnota je naplněna, pokud seznam strukturálně odpovídá vzorku:

def list_type(x):
    match x:
        case [a, b]:
            return f"list with two items: {a} and {b}"
        case [a]:
            return f"list with one item: {a}"
        case []:
            return "empty list"
        case _ as lst:
            return f"list with {len(lst)} items"
 
 
print(list_type([]))
print(list_type(["x"]))
print(list_type(["x", "y"]))
print(list_type(["x", "y", "z"]))

14. Chování skriptu ve chvíli, kdy funkci není předán seznam

Ve skutečnosti není předchozí skript (opět) zcela korektní, protože nedokáže adekvátně zareagovat v situaci, kdy do funkce list_type předáme hodnotu odlišného typu. V některých případech se (a to pochopitelně chybně) vypíše délka této hodnoty, ovšem pokud nebude standardní funkce len na předanou hodnotu aplikovatelná, dojde k vyhození výjimky:

def list_type(x):
    match x:
        case [a, b]:
            return f"list with two items: {a} and {b}"
        case [a]:
            return f"list with one item: {a}"
        case []:
            return "empty list"
        case _ as lst:
            return f"list with {len(lst)} items"
 
 
print(list_type("Hello!"))
print(list_type(42))

Výsledky ukazují nekorektní reakci na chyby:

list with 6 items
Traceback (most recent call last):
  File "<frozen runpy>", line 291, in run_path
  File "<frozen runpy>", line 98, in _run_module_code
  File "<frozen runpy>", line 88, in _run_code
  File "/home/ptisnovs/src/most-popular-python-libs/coconut/pattern-matching-8-error.py", line 2945, in <module>
    print(list_type(42))  #14 (line in Coconut source)
          ^^^^^^^^^^^^^
  File "/home/ptisnovs/src/most-popular-python-libs/coconut/pattern-matching-8-error.py", line 672, in tail_call_optimized_func
    result = call_func(*args, **kwargs)  # use 'coconut --no-tco' to clean up your traceback
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ptisnovs/src/most-popular-python-libs/coconut/pattern-matching-8-error.py", line 2940, in list_type
    return _coconut_tail_call("list with {_coconut_format_0} items".format, _coconut_format_0=(len(lst)))  #10 (line in Coconut source)
                                                                                                ^^^^^^^^
TypeError: object of type 'int' has no len()

15. Kontrola, zda je předán seznam

Tomuto chování zabráníme způsobem, který již známe – přidáme do poslední větve kontrolu, zda se skutečně jedná o seznam. A navíc do celého bloku match přidáme větev else, která se vykoná ve chvíli, kdy žádný vzorek neodpovídá předaným datům:

def list_type(x):
    match x:
        case [a, b]:
            return f"list with two items: {a} and {b}"
        case [a]:
            return f"list with one item: {a}"
        case []:
            return "empty list"
        case list(lst):
            return f"list with {len(lst)} items"
    else:
        return "wrong type"
 
 
print(list_type([]))
print(list_type(["x"]))
print(list_type(["x", "y"]))
print(list_type(["x", "y", "z"]))
print(list_type("foo"))

Alternativně je možné použít syntaxi kompatibilní s Pythonem, tj. namísto větve else se použije univerzální vzorek zapisovaný znakem _. Tomuto vzorku odpovídá jakýkoli vstup:

def list_type(x):
    match x:
        case [a, b]:
            return f"list with two items: {a} and {b}"
        case [a]:
            return f"list with one item: {a}"
        case []:
            return "empty list"
        case list(lst):
            return f"list with {len(lst)} items"
        case _:
            return "wrong type"
 
 
print(list_type([]))
print(list_type(["x"]))
print(list_type(["x", "y"]))
print(list_type(["x", "y", "z"]))
print(list_type("foo"))

16. Realizace komplexních čísel s využitím n-tice s reálnou a imaginární hodnotou

Vyzkoušejme si nyní jednu možnou realizaci komplexních čísel, a to konkrétně takovým způsobem, že jejich reálná a imaginární složka bude uložena do dvojice (což je specializace n-tice neboli typu tuple). Ve funkci nazvané complex_number se budeme rozhodovat, jaká forma komplexního čísla je do této funkce předána. Může se jednat o komplexní nulu, dále o komplexní číslo s nulovou imaginární složkou, o komplexní číslo s nulovou reálnou složkou, nebo o obecné komplexní číslo. Pro rozhodování pochopitelně opět použijeme pattern matching:

def complex_number(value):
    """Test, o jakou variantu komplexního čísla se jedná."""
    match value:
        case (0, 0):
            print("Zero")
        case (real, 0):
            print(f"Real number {real}")
        case (0, imag):
            print(f"Imaginary number {imag}")
        case (real, imag):
            print(f"Complex number {real}+i{imag}")
        case _:
            raise ValueError("Not a complex number")
 
 
complex_number((0,0))
complex_number((1,0))
complex_number((0,1))
complex_number((1,1))
complex_number("foo")
Poznámka: v tomto algoritmu není možné jednotlivé větve prohazovat, protože speciální případy musí být uvedeny na začátku (a první případ je nejvíce specializovaný, naopak poslední větev vyhovuje všem předaným hodnotám).

17. Test, zda je reálná a/nebo imaginární složka komplexního čísla reprezentovaná numerickou hodnotou

Test z předchozí kapitoly si můžeme rozšířit a zjišťovat, zda je reálná a/nebo imaginární složka komplexního čísla reprezentovaná numerickou hodnotou (typem int, ale můžete použít i number), nebo zda je zadána jiným způsobem, například s využitím datového typu „zlomek“ atd. Opět si povšimněte, že nejdříve jsou uvedeny speciální případy a směrem dolů (při pohledu na zdrojový kód) se „šíře záběru“ jednotlivých vzorků rozšiřuje:

def complex_number(value):
    """Test, o jakou variantu komplexního čísla se jedná."""
    match value:
        case (0, 0):
            print("Zero")
        case (int(real), 0):
            print(f"Real number {real}")
        case (real, 0):
            print(f"Strange real number {real}, value is not integer")
        case (0, int(imag)):
            print(f"Imaginary number {imag}")
        case (0, imag):
            print(f"Strange imaginary number {imag}, value is not integer")
        case (int(real), int(imag)):
            print(f"Complex number {real}+i{imag}")
        case (real, imag):
            print(f"Strange complex number {real}+i{imag}, real and imaginary part should be integers")
        case _:
            raise ValueError("Not a complex number")
 
 
complex_number((0,0))
complex_number((1,0))
complex_number((0,1))
complex_number((1,1))
 
complex_number(("x", 0))
complex_number((0, "y"))
complex_number(("x", "y"))
 
complex_number("foo")
complex_number("foo")

Triviálním způsobem můžeme testy upravit tak, aby se namísto dvojic (specializovaná n-tice) mohly používat i dvouprvkové seznamy:

def complex_number(value):
    """Test, o jakou variantu komplexního čísla se jedná."""
    match value:
        case [0, 0]:
            print("Zero")
        case [int(real), 0]:
            print(f"Real number {real}")
        case [real, 0]:
            print(f"Strange real number {real}, value is not integer")
        case [0, int(imag)]:
            print(f"Imaginary number {imag}")
        case [0, imag]:
            print(f"Strange imaginary number {imag}, value is not integer")
        case [int(real), int(imag)]:
            print(f"Complex number {real}+i{imag}")
        case [real, imag]:
            print(f"Strange complex number {real}+i{imag}, real and imaginary part should be integers")
        case _:
            raise ValueError("Not a complex number")
 
 
complex_number([0,0])
complex_number([1,0])
complex_number([0,1])
complex_number([1,1])
 
complex_number(["x", 0])
complex_number([0, "y"])
complex_number(["x", "y"])
 
complex_number("foo")
complex_number("foo")

18. Další možnosti poskytované programovacím jazykem Coconut v oblasti pattern matchingu

V jazyku Coconut je ve skutečnosti možné používat i další formy pattern matchingu, přičemž většina z nich není kompatibilní s Pythonem (možná s budoucími verzemi):

CS24_early

  1. Vzorek může obsahovat části seznamu (začátek – head) a zbylé prvky se vloží do příslušného zástupného symbolu
  2. Vzorek může obsahovat části seznamu (konec – tail) a zbylé prvky se vloží do příslušného zástupného symbolu
  3. Vzorek může být kombinací obou předchozích možností
  4. Vzorek může být část řetězce, přičemž jeho „proměnná část“ se uloží do zástupného symbolu
  5. Zástupné symboly mohou být uvedeny i u slovníku a množiny (kompatibilní s Pythonem)
  6. Zástupné symboly mohou být uvedeny i u multimnožiny
  7. Vzorek může obsahovat i třídu se specifikací povinných atributů (opět nelze vyřešit přímo v Pythonu)
  8. Lze definovat i různé varianty funkce v závislosti na vzorku (viz jazyk ML)

S těmito vlastnostmi pattern matchingu v programovacím jazyku Coconut se seznámíme v navazujícím článku.

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

Zdrojové kódy všech prozatím popsaných demonstračních příkladů určených pro programovací jazyk Coconut byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs.

# Příklad Stručný popis Adresa
1 hello-world.coco Program typu „Hello, world“ naprogramovaný v jazyce Coconut https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/hello-world.coco
2 hello-world.py překlad pipeline s voláním funkce print do Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/hello-world.py
3 hello-world-non-optim.py ukázka celého souboru (čistý Python), který vznikne výsledkem transpřekladu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/hello-world-non-optim.py
4 hello-world-minified.py ukázka celého souboru (čistý Python), který vznikne výsledkem transpřekladu s povolenou minifikací https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/hello-world-minified.py
       
5 lambda-old-style.coco zápis anonymní funkce s využitím operátoru → (původní styl Pythonu) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-old-style.coco
6 lambda-old-style.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-old-style.py
7 lambda-new-style.coco zápis anonymní funkce s využitím operátoru ⇒ (doporučovaný styl) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-new-style.coco
8 lambda-new-style.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-new-style.py
       
9 original-factorial-1.py výpočet faktoriálu naprogramovaný v Pythonu: použití anonymní funkce https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-factorial-1.py
10 original-factorial-2.py výpočet faktoriálu naprogramovaný v Pythonu: vnořené anonymní funkce https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-factorial-2.py
11 original-factorial-3.py výpočet tabulky s faktoriály bez použití programových smyček https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-factorial-3.py
       
12 lambda-factorial-1.coco výpočet faktoriálu s anonymní funkcí se dvěma parametry (nekorektní zápis) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-1.coco
13 lambda-factorial-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-1.py
14 lambda-factorial-2.coco výpočet faktoriálu s anonymní funkcí se dvěma parametry (korektní zápis) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-2.coco
15 lambda-factorial-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-2.py
16 lambda-factorial-3.coco vnořené anonymní funkce https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-3.coco
17 lambda-factorial-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-3.py
18 lambda-factorial-4.coco výpočet tabulky s faktoriály bez použití programových smyček https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-4.coco
19 lambda-factorial-4.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-4.py
20 lambda-factorial-5.coco výpočet tabulky s faktoriály bez použití programových smyček + použití pipe https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-5.coco
21 lambda-factorial-5.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/lambda-factorial-5.py
       
22 implicit-lambda-1.coco lambda výraz s implicitním parametrem https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/implicit-lambda-1.coco
23 implicit-lambda-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/implicit-lambda-1.py
24 implicit-lambda-2.coco lambda výraz bez parametru https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/implicit-lambda-2.coco
25 implicit-lambda-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/implicit-lambda-2.py
       
26 statement-lambda-1.coco plnohodnotná anonymní funkce https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-1.coco
27 statement-lambda-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-1.py
28 statement-lambda-2.coco anonymní funkce s příkazem a výrazem https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-2.coco
29 statement-lambda-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-2.py
       
30 statement-lambda-type-hints.coco anonymní funkce s typovými informacemi https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-type-hints.coco
31 statement-lambda-type-hints-python-2.py výsledek překladu skriptu do standardního Pythonu verze 2 https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-type-hints-python-2.py
32 statement-lambda-type-hints-python-3.py výsledek překladu skriptu do standardního Pythonu verze 3 https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/statement-lambda-type-hints-python-3.py
       
33 original-partial-1.py částečně vyhodnocená funkce, realizace provedená ve standardním Pythonu, první verze (funkce se dvěma parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-partial-1.py
34 original-partial-2.py částečně vyhodnocená funkce, realizace provedená ve standardním Pythonu, druhá verze (funkce se třemi parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-partial-2.py
35 original-partial-3.py částečně vyhodnocená funkce, realizace provedená ve standardním Pythonu, třetí verze (funkce se čtyřmi parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/original-partial-3.py
       
36 partial-1.coco částečně vyhodnocená funkce zapsaná v jazyku Coconut, první verze (funkce se dvěma parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-1.coco
37 partial-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-1.py
38 partial-2.coco částečně vyhodnocená funkce zapsaná v jazyku Coconut, druhá verze (funkce se třemi parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-2.coco
39 partial-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-2.py
40 partial-3.coco částečně vyhodnocená funkce zapsaná v jazyku Coconut, třetí verze (funkce se čtyřmi parametry) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-3.coco
41 partial-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-3.py
       
42 partial-map.coco částečně vyhodnocená funkce vyššího řádu fmap https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-map.coco
43 partial-map.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/partial-map.py
       
44 sequences1A.coco ukázka rozdílu v chování funkcí map a fmap https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1A.coco
45 sequences1A.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1A.py
46 sequences1B.coco přepis předchozího demonstračního příkladu tak, že se využije zkrácený zápis lambda výrazů https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1B.coco
47 sequences1B.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1B.py
48 sequences1C.coco přepis předchozího demonstračního příkladu tak, že se využije zkrácený zápis lambda výrazů s implicitním parametrem https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1C.coco
49 sequences1C.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences1C.py
50 sequences2A.coco ukázka funkcí reduce, takewhile a dropwhile https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2A.coco
51 sequences2A.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2A.py
52 sequences2B.coco přepis předchozího demonstračního příkladu tak, že se využije zkrácený zápis lambda výrazů https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2B.coco
53 sequences2B.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2B.py
54 sequences2C.coco přepis předchozího demonstračního příkladu tak, že se využije zkrácený zápis lambda výrazů s implicitním parametrem https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2C.coco
55 sequences2C.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/se­quences2C.py
       
56 custom-operator-1.coco vytvoření nového binárního operátoru https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-1.coco
57 custom-operator-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-1.py
58 custom-operator-2.coco vytvoření nového binárního operátoru https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-2.coco
59 custom-operator-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-2.py
60 custom-operator-3.coco vytvoření nového unárního operátoru https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-3.coco
61 custom-operator-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/custom-operator-3.py
       
62 infix-notation-1.coco infixový zápis volání funkce add https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-1.coco
63 infix-notation-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-1.py
64 infix-notation-2.coco infixový zápis volání funkce factorial https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-2.coco
65 infix-notation-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-2.py
66 infix-notation-3.coco infixová definice funkce nad https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-3.coco
67 infix-notation-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-3.py
68 infix-notation-4.coco infixový zápis volání funkcí a priorita operací https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-4.coco
69 infix-notation-4.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/infix-notation-4.py
       
70 py3-only-async-await.coco konstrukce platná pouze v Pythonu 3.x – asyncawait https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-async-await.coco
71 py3-only-async-await.py výsledek překladu skriptu do standardního Pythonu verze 3.x https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-async-await.py
72 py3-only-counter_closure.coco konstrukce platná pouze v Pythonu 3.x – nelokální proměnná https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-counter_closure.coco
73 py3-only-counter_closure.py výsledek překladu skriptu do standardního Pythonu verze 3.x https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-counter_closure.py
74 py3-only-walrus-operator.coco konstrukce platná pouze v Pythonu 3.x – mroží operátor https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-walrus-operator.coco
75 py3-only-walrus-operator.py výsledek překladu skriptu do standardního Pythonu verze 3.x https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/py3-only-walrus-operator.py
       
76 pipeline-basic.coco základní forma kolony, v níž data proudí zleva doprava https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-basic.coco
77 pipeline-basic.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-basic.py
78 pipeline-backward.coco základní forma kolony, v níž data proudí zprava doleva https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward.coco
79 pipeline-backward.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward.py
       
80 pipeline-none-not-aware.coco kolona, která nerozeznává hodnoty None https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-not-aware.coco
81 pipeline-none-not-aware.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-not-aware.py
82 pipeline-none-aware.coco kolona, která rozeznává hodnoty None https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-aware.coco
83 pipeline-none-aware.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-aware.py
84 pipeline-none-aware-2.coco kolona, která rozeznává hodnoty None, explicitní tisk výsledků https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-aware-2.coco
85 pipeline-none-aware-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-none-aware-2.py
       
86 pipeline-backward-none-not-aware.coco „zpětná“ kolona, která nerozeznává hodnoty None https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward-none-not-aware.coco
87 pipeline-backward-none-not-aware.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward-none-not-aware.py
88 pipeline-backward-none-aware.coco „zpětná“ kolona, která rozeznává hodnoty None https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward-none-aware.coco
89 pipeline-backward-none-aware.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-backward-none-aware.py
       
90 pipeline-multiple-arguments.coco kolona přenášející větší množství argumentů mezi funkcemi https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-multiple-arguments.coco
91 pipeline-multiple-arguments.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-multiple-arguments.py
92 pipeline-multiple-arguments-2.coco použití standardního operátoru pro rozdíl v koloně https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-multiple-arguments-2.coco
93 pipeline-multiple-arguments-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-multiple-arguments-2.py
94 pipeline-keyword-arguments.coco kolona přenášející keyword argumenty https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-keyword-arguments.coco
95 pipeline-keyword-arguments.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pipeline-keyword-arguments.py
       
96 function-composition-1.coco použití kompozice funkcí v koloně https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-1.coco
97 function-composition-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-1.py
98 function-composition-2.coco uložení kompozice funkcí do nového symbolu (nové funkce) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-2.coco
99 function-composition-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-2.py
100 function-composition-3.coco kompozice funkcí operátorem <.. https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-3.coco
101 function-composition-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-3.py
102 function-composition-4.coco kompozice funkcí a hodnota None https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-4.coco
103 function-composition-4.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/function-composition-4.py
       
104 pattern-matching-1.coco výpočet faktoriálu realizovaný v původní syntaxi jazyka Coconut https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-1.coco
105 pattern-matching-1.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-1.py
106 pattern-matching-2.coco výpočet faktoriálu realizovaný v syntaxi jazyka Coconut kompatibilní s Pythonem 3.10 https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-2.coco
107 pattern-matching-2.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-2.py
108 pattern-matching-3.coco ve větvi s rekurzí se kontroluje, zda je vstupní hodnota kladná https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-3.coco
109 pattern-matching-3.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-3.py
110 pattern-matching-4.coco test na typ předané hodnoty (původní syntaxe) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-4.coco
111 pattern-matching-4.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-4.py
112 pattern-matching-5.coco test na typ předané hodnoty (nová syntaxe) https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-5.coco
113 pattern-matching-5.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-5.py
114 pattern-matching-6.coco spojení dvou vzorků pomocí operátoru | https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-6.coco
115 pattern-matching-6.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-6.py
       
116 pattern-matching-7.coco zjištění, kolik prvků obsahuje sezname https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-7.coco
117 pattern-matching-7.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-7.py
118 pattern-matching-8.coco vylepšení předchozího příkladu, tisk hodnot prvků ze seznamu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-8.coco
119 pattern-matching-8.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-8.py
120 pattern-matching-9.coco test, zda je do funkce list_type předán skutečně seznam, první varianta https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-9.coco
121 pattern-matching-9.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-9.py
122 pattern-matching-A.coco test, zda je do funkce list_type předán skutečně seznam, druhá varianta https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-A.coco
123 pattern-matching-A.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-A.py
       
124 pattern-matching-B.coco pattern matching a dvojice hodnot představujících komplexní čísla https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-B.coco
125 pattern-matching-B.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-B.py
126 pattern-matching-C.coco detekce, zda není reálná nebo imaginární složka komplexního čísla nulová https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-C.coco
127 pattern-matching-C.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-C.py
128 pattern-matching-D.coco dtto, ovšem využití seznamu s dvojicí hodnot namísto n-tice https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-D.coco
129 pattern-matching-D.py výsledek překladu skriptu do standardního Pythonu https://github.com/tisnik/most-popular-python-libs/blob/master/coconut/pattern-matching-D.py

20. Odkazy na Internetu

  1. Pattern matching (Wikipedia)
    https://en.wikipedia.org/wi­ki/Pattern_matching
  2. Coconut: funkcionální jazyk s pattern matchingem kompatibilní s Pythonem
    https://www.root.cz/clanky/coconut-funkcionalni-jazyk-s-pattern-matchingem-kompatibilni-s-pythonem/
  3. Coconut aneb funkcionální nadstavba nad Pythonem (2.část)
    https://www.root.cz/clanky/coconut-aneb-funkcionalni-nadstavba-nad-pythonem-2-cast/
  4. Python 3.10 and the Elegance of Pattern Matching
    https://python.plainenglish.io/python-3–10-and-the-elegance-of-pattern-matching-2620a02b2379
  5. More Pattern Matching in Python 3.10
    https://towardsdatascience.com/more-advanced-pattern-matching-in-python-3–10–2dbd8598302a
  6. Pattern Matching in Python 3.10
    https://towardsdatascience.com/pattern-matching-in-python-3–10–6124ff2079f0
  7. Python 3.10.0
    https://www.python.org/dow­nloads/release/python-3100/
  8. The fate of reduce() in Python 3000
    http://lambda-the-ultimate.org/node/587
  9. PEP 634 – Structural Pattern Matching: Specification
    https://peps.python.org/pep-0634/
  10. PEP 635 – Structural Pattern Matching: Motivation and Rationale
    https://peps.python.org/pep-0635/
  11. PEP 636 – Structural Pattern Matching: Tutorial
    https://peps.python.org/pep-0636/
  12. PEP 622 – Structural Pattern Matching
    https://peps.python.org/pep-0622/
  13. Python 3.10 se strukturálním pattern matchingem
    https://www.root.cz/zpravicky/python-3–10-se-strukturalnim-pattern-matchingem/
  14. Null coalescing operator
    https://en.wikipedia.org/wi­ki/Null_coalescing_operator
  15. Operátor koalescence
    https://cs.wikipedia.org/wi­ki/Oper%C3%A1tor_koalescen­ce
  16. Clojure core.match
    https://github.com/clojure/core.match
  17. The Rust Programming Language: Patterns and Matching
    https://doc.rust-lang.org/book/ch18–00-patterns.html#patterns-and-matching
  18. The Rust Programming Language: Pattern Syntax
    https://doc.rust-lang.org/book/ch18–03-pattern-syntax.html
  19. Elvis operator
    https://en.wikipedia.org/wi­ki/Elvis_operator
  20. Safe navigation operator
    https://en.wikipedia.org/wi­ki/Safe_navigation_operator
  21. Setting stacksize in a python script
    https://stackoverflow.com/qu­estions/5061582/setting-stacksize-in-a-python-script
  22. What is the maximum recursion depth in Python, and how to increase it?
    https://stackoverflow.com/qu­estions/3323001/what-is-the-maximum-recursion-depth-in-python-and-how-to-increase-it?rq=1
  23. Does Python optimize tail recursion?
    https://stackoverflow.com/qu­estions/13591970/does-python-optimize-tail-recursion
  24. Programovací jazyk APL: programování bez smyček
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-programovani-bez-smycek/
  25. Programovací jazyk APL – dokončení
    https://www.root.cz/clanky/pro­gramovaci-jazyk-apl-dokonceni/
  26. Tail call
    https://en.wikipedia.org/wi­ki/Tail_call
  27. Tail Call Optimization for Python
    https://github.com/baruchel/tco
  28. Tail Recursion Elimination
    http://neopythonic.blogspot­.cz/2009/04/tail-recursion-elimination.html
  29. Origins of Python's „Functional“ Features
    http://python-history.blogspot.cz/2009/04/origins-of-pythons-functional-features.html
  30. Tail recursion decorator revisited
    http://fiber-space.de/wordpress/2009/04/20/tail-recursion-decorator-revisited/
  31. Koncová rekurze
    https://cs.wikipedia.org/wi­ki/Koncov%C3%A1_rekurze
  32. Recursion (computer science)
    https://en.wikipedia.org/wi­ki/Recursion_%28computer_sci­ence%29
  33. Coconut: Simple, elegant, Pythonic functional programming
    http://coconut-lang.org/
  34. coconut 1.1.0 (Python package index)
    https://pypi.python.org/py­pi/coconut/1.1.0
  35. Coconut Tutorial
    http://coconut.readthedoc­s.io/en/master/HELP.html
  36. Coconut FAQ
    http://coconut.readthedoc­s.io/en/master/FAQ.html
  37. Coconut Documentation
    http://coconut.readthedoc­s.io/en/master/DOCS.html
  38. Python gains functional programming syntax via Coconut
    https://www.infoworld.com/ar­ticle/3088058/python-gains-functional-programming-syntax-via-coconut.html
  39. Repositář projektu pyparsing
    https://github.com/pyparsin­g/pyparsing
  40. Repositář projektu cPyparsing
    https://github.com/evhub/cpyparsing
  41. Projekty vylepšující interaktivní režim Pythonu: bpython, ptpython, DreamPie a IPython
    https://www.root.cz/clanky/projekty-vylepsujici-interaktivni-rezim-pythonu-bpython-ptpython-dreampie-a-ipython/
  42. Coconut na Redditu
    https://www.reddit.com/r/Pyt­hon/comments/4owzu7/coconut_fun­ctional_programming_in_pyt­hon/
  43. Repositář na GitHubu
    https://github.com/evhub/coconut
  44. patterns
    https://github.com/Suor/patterns
  45. Source-to-source compiler
    https://en.wikipedia.org/wiki/Source-to-source_compiler
  46. The Lua VM, on the Web
    https://kripken.github.io/lu­a.vm.js/lua.vm.js.html
  47. Lua.vm.js REPL
    https://kripken.github.io/lu­a.vm.js/repl.html
  48. lua2js
    https://www.npmjs.com/package/lua2js
  49. Wisp na GitHubu
    https://github.com/Gozala/wisp
  50. Wisp playground
    http://www.jeditoolkit.com/try-wisp/
  51. REPL v prohlížeči
    http://www.jeditoolkit.com/in­teractivate-wisp/
  52. Minification (programming)
    https://en.wikipedia.org/wi­ki/Minification_(programmin­g)
  53. JavaScript is Assembly Language for the Web: Sematic Markup is Dead! Clean vs. Machine-coded HTML
    http://www.hanselman.com/blog/Ja­vaScriptIsAssemblyLanguage­ForTheWebSematicMarkupIsDe­adCleanVsMachinecodedHTML­.aspx
  54. JavaScript is Web Assembly Language and that's OK.
    http://www.hanselman.com/blog/Ja­vaScriptIsWebAssemblyLangu­ageAndThatsOK.aspx
  55. Dart
    https://www.dartlang.org/
  56. CoffeeScript
    http://coffeescript.org/
  57. TypeScript
    http://www.typescriptlang.org/
  58. JavaScript: The Web Assembly Language?
    http://www.informit.com/ar­ticles/article.aspx?p=1856657
  59. asm.js
    http://asmjs.org/
  60. List of languages that compile to JS
    https://github.com/jashke­nas/coffeescript/wiki/List-of-languages-that-compile-to-JS
  61. Permutation
    https://en.wikipedia.org/wi­ki/Permutation
  62. Pattern matching (Wikipedia)
    https://en.wikipedia.org/wi­ki/Pattern_matching
  63. Programovací jazyky používané v SSSR (část 2 – SNOBOL)
    https://www.root.cz/clanky/pro­gramovaci-jazyky-pouzivane-v-sssr-cast-2-ndash-snobol/
  64. Pattern matching v Rustu
    https://www.root.cz/clanky/rust-funkce-lambda-vyrazy-a-rozhodovaci-konstrukce-match/#k13
  65. SNOBOL
    https://en.wikipedia.org/wiki/SNOBOL
  66. Podpůrný plugin pro Vim
    https://github.com/manicma­niac/coconut.vim
  67. Příkaz (programování)
    https://cs.wikipedia.org/wi­ki/P%C5%99%C3%ADkaz_%28pro­gramov%C3%A1n%C3%AD%29
  68. Threading Macros Guide
    https://clojure.org/guides/thre­ading_macros
  69. Nejdůležitější novinka v Pythonu 3.10: strukturální pattern matching
    https://www.root.cz/clanky/nej­dulezitejsi-novinka-v-pythonu-3–10-strukturalni-pattern-matching/
  70. Rosetta Code: Roman_numerals
    http://rosettacode.org/wi­ki/Roman_numerals
  71. Category:SNOBOL4
    http://rosettacode.org/wi­ki/Category:SNOBOL4
  72. An introduction to SNOBOL by James Ford
    http://drofmij.awardspace.com/snobol/
  73. AWK
    https://en.wikipedia.org/wiki/AWK
  74. Get started with GAWK: AWK language fundamentals
    https://web.archive.org/web/20150427143548/htt­ps://www6.software.ibm.com/de­veloperworks/education/au-gawk/au-gawk-a4.pdf
  75. Pattern Matching
    https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/pattern-matching
  76. Parsing expression grammar
    https://en.wikipedia.org/wi­ki/Parsing_expression_gram­mar
  77. Abort, Retry, Fail?
    https://en.wikipedia.org/wi­ki/Abort,_Retry,_Fail%3F
  78. SNOBOL4 and SPITBOL Information
    http://www.snobol4.com/
  79. Vanilla Snobol4 Reference Manual
    http://burks.bton.ac.uk/bur­ks/language/snobol/catspaw/ma­nual/contents.htm
  80. SNOBOL4.ORG – SNOBOL4 Resources
    http://www.snobol4.org/
  81. Snobol3 – Snobol 3 Interpreter Implemented in Java
    http://serl.cs.colorado.e­du/~dennis/software/s3.html
  82. Exploring Beautiful Languages – A guick look at SNOBOL
    http://langexplr.blogspot­.com/2007/12/quick-look-at-snobol.html
  83. Rekurze a pattern matching v programovacím jazyku F#
    https://www.root.cz/clanky/rekurze-a-pattern-matching-v-programovacim-jazyku-f/
  84. Programovací jazyk OCaml: rekurze, pattern matching a práce se seznamy
    https://www.root.cz/clanky/pro­gramovaci-jazyk-ocaml-rekurze-pattern-matching-a-prace-se-seznamy/
ikonka

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.

Byl pro vás článek přínosný?

Autor článku

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