Projekt py2many: transpiler Pythonu do dalších programovacích jazyků

18. 6. 2024
Doba čtení: 32 minut

Sdílet

 Autor: Root.cz s využitím DALL-E
V dnešním článku se seznámíme se základními vlastnostmi projektu py2many, který dokáže překládat zdrojové kódy z Pythonu do dalších jazyků, včetně C++, Rustu, Go či jazyku Julia.

Obsah

1. Transpiling – překlad zdrojových kódů Pythonu do dalších programovacích jazyků

2. Projekt py2many

3. Syntaktické a sémantické rozdíly mezi podporovanými jazyky

4. Python vs. ostatní jazyky

5. Instalace transpřekladače py2many

6. Podpůrné nástroje pro naformátování výsledných zdrojových kódů podle zvyklostí cílového programovacího jazyka

7. Transpřeklad programu typu „Hello, world!“

8. Program obsahující pouze definici jediné funkce

9. Definice funkce s voláním této funkce

10. Výpočet faktoriálu realizovaný funkcí bez typových informací

11. Ackermannova funkce definovaná bez použití datových typů

12. Ackermannova funkce definovaná s využitím typových informací

13. Funkce s implementací algoritmu bublinkového řazení

14. Datové typy v programovacím jazyce Python i v jazycích, do nichž je transpilován

15. Základní operace se seznamy: varianta s datovými typy i bez typů

16. Výsledek transpilace kódu, v němž nebyly použity typové informace

17. Výsledek transpilace kódu, v němž byly použity typové informace

18. Tabulka se srovnáním úspěchu transpřekladu jednotlivých příkladů

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

20. Odkazy na Internetu

1. Transpiling – překlad zdrojových kódů Pythonu do dalších programovacích jazyků

Na stránkách Roota jsme se již několikrát setkali s projekty, ve kterých byla realizována nějaká forma transpilace (nebo transkompilace). Takže si jen ve stručnosti připomeňme, že takzvaný transcompiler, popř. zkráceně transpiler slouží k převodu zdrojového kódu z jednoho programovacího jazyka do jazyka jiného, na rozdíl od běžných překladačů (compiler), které provádí překlad buď do nativního kódu nebo do bajtkódu (bytecode). Překladače do nativního kódu asi netřeba představovat – patří sem totiž klasické překladače céčka, Rustu, Go atd. (což ve skutečnosti je nepatrně složitější v případě LLVM, to je však téma na samostatný článek). A ani překladače do bajtkódu nejsou ve světě moderní informatiky neznámé (spíš naopak), protože z používaných prostředků sem spadá především Java, Python (soubory .pyc) a překladače podporující WebAssemly (WASM).

Aktivně používaných transpilerů taktéž v současnosti existuje celá řada, přičemž některé z nich mají za úkol „snížení úrovně abstrakce“, tedy například transpilaci z Pythonu či jiného vysokoúrovňového jazyka do programovacího jazyka C s následným překladem výsledného kódu s využitím nějakého kvalitního a optimalizujícího překladače céčka (příkladem může být projekt Cython, který již taktéž známe). Další transpilery vznikly pro podporu dalších programovacích jazyků v těch ekosystémech, které jsou (z různých důvodů) navázány na jediný programovací jazyk. Dnes je naprosto nejtypičtějším příkladem takového ekosystému svět webových prohlížečů, který se ustálil na podpoře JavaScriptu a projekty psané v jiných programovacích jazycích je tak nutné buď transpilovat právě do JavaScriptu (popř. do jeho podmnožiny – sem spadá projekt ams.js) nebo mít v JavaScriptu či WASM naprogramovaný interpret daného jazyka se všemi z toho plynoucími důsledky (rychlost, objem stahovaných dat apod.).

2. Projekt py2many

V dnešním článku se seznámíme s projektem nazvaným py2many, který si klade zajímavý cíl. Tímto cílem je umožnění transpilace zdrojových kódů z jazyka Python do několika dalších programovacích jazyků, tedy nikoli pouze do jediného cílového jazyka. V současnosti v tomto projektu existuje podpora pro několik cílových jazyků. Zejména zde nalezneme Rust a C++, na které se soustřeďuje další vývoj (zejména na Rust, to ostatně uvidíme i v demonstračních příkladech), ovšem nalezneme zde i další cílové jazyky, a to konkrétně programovací jazyky Go, Julia, Kotlin, Nim, Dart a taktéž jazyk V.

Ovšem jak uvidíme v dalším textu, podpora nějakého cílového jazyka neznamená, že by bylo možné vzít složitý projekt psaný v Pythonu, transpřeložit ho do (řekněme) zdrojových kódů psaných v Go a poté ho bez problémů přeložit překladačem Go a spustit. Na cestě stojí několik více či méně závažných překážek, ale i přesto může být tento projekt zajímavý a to především proto, že programovací jazyk Python (resp. jeho „osekaná“ varianta) je dnes často používán v učebnicích, odborných článcích atd. pro zápis popisovaných algoritmů; Python zde tedy vystupuje v roli abstraktního jazyka vhodného pro tyto účely, tedy pro zápis pseudokódu (ale opět – jedná se typicky o Python „osekaný“ o některé nové vlastnosti). A díky py2many je možné takový algoritmus ve více či méně korektní podobě získat i pro další konkrétní programovací jazyk.

Poznámka: nenechte se zmást číslicí 2 v názvu py2many. Ta nemá nic společného s Pythonem verze 2 (vzpomínáme…) ale jedná se o v IT poměrně často používanou slovní hříčku „py t(w)o many“.

3. Syntaktické a sémantické rozdíly mezi podporovanými jazyky

Ještě předtím, než si ukážeme demonstrační příklady, na nichž budou patrné vlastnosti (a především nedostatky) projektu py2many, je dobré si uvědomit, jak odlišné jsou programovací jazyky, do nichž je programový kód napsaný v Pythonu transpilován. Liší se pochopitelně syntaxe, klíčová slova, pravidla pro psaní závorek a středníků atd. To však není vlastně příliš důležité, protože mnohem větší rozdíly nalezneme v sémantice použitých programovacích jazyků.

Začněme Pythonem, což je programovací jazyk, v němž nalezneme podporu pro funkce jako plnohodnotných datových typů, je možné používat uzávěry, funkce mohou mít proměnný počet parametrů, funkce mohou akceptovat keyword parametry, Python podporuje objektově orientované programování založené na třídách, lze vytvářet konstrukce pro zachytávání výjimek, podporován je pattern matching, aplikace dekorátorů a v neposlední řadě i asynchronní programování realizované mj. i klíčovými slovy async a await. A navíc Python podporuje i zdánlivou maličkost – přímý zápis příkazů, které nemusí být umístěny v žádné funkci nebo v metodě.

4. Python vs. ostatní jazyky

Naproti tomu u prakticky všech programovacích jazyků, do nichž nástroj py2many dokáže Python transpilovat, některou z těchto vlastností nenalezneme (resp. většinou jich nenalezneme větší množství). Z těchto důvodů si v praktické části dnešního článku postupně ukážeme, jak dobře, špatně, či dokonce vůbec jsou některé jazykové konstrukce Pythonu překládány do dalších jazyků. Trošku sice předběhneme výsledky, ke kterým postupně dospějeme, ale ukazuje se, že nejlépe je podporován programovací jazyk Rust. To může vypadat zvláštně, protože Rust nepodporuje například klasické objektově orientované programování realizované třídami nebo programovou konstrukci typu try-catch-finally. Pro další konstrukce je korektní (trans)překlad i do programovacího jazyka Julia, ovšem například C++ či Go dopadají v tomto porovnání poněkud hůře (a to se nesnažím být příliš kritický).

5. Instalace transpřekladače py2many

Samotný nástroj py2many může být nainstalován a spouštěn i bez toho, aby byly k dispozici nainstalované cílové programovací jazyky, ovšem v některých případech nebudou určité operace provedeny (například naformátování výsledného kódu). Nejprve si tedy py2many nainstalujeme, což je ve skutečnosti velmi snadné, protože má jen minimální závislosti a lze ho nainstalovat standardním nástrojem pip z ekosystému programovacího jazyka Python:

$ pip3 install --user py2many

Průběh instalace naznačuje, že závislosti na dalších balíčcích Pythonu jsou jen minimální:

Collecting py2many
  Downloading py2many-0.4.tar.gz (231 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 231.8/231.8 kB 2.1 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Collecting toposort
  Downloading toposort-1.10-py3-none-any.whl (8.5 kB)
Building wheels for collected packages: py2many
  Building wheel for py2many (setup.py) ... done
  Created wheel for py2many: filename=py2many-0.4-py3-none-any.whl size=135227 sha256=fdee7d3e80a45ee303084aa6db3aa5a7568c1a18eb4e6f071b1fbd502ce751ec
  Stored in directory: /home/ptisnovs/.cache/pip/wheels/e0/90/16/93e6e6033164b1c0391430e30ce0ba0ef247c24d3a93c25d36
Successfully built py2many
Installing collected packages: toposort, py2many
Successfully installed py2many-0.4 toposort-1.10

6. Podpůrné nástroje pro naformátování výsledných zdrojových kódů podle zvyklostí cílového programovacího jazyka

Samotný transpřekladač py2many sice dokáže generovat zdrojové kódy pro zvolený cílový jazyk, ovšem naformátování těchto kódů nemusí odpovídat zvyklostem, které jsou v cílovém ekosystému dodržovány. Týká se to především ekosystémů okolo programovacích jazyků Rust a Go, v nichž se poměrně striktně dodržuje určitá štábní kultura. Aby výsledné zdrojové kódy do těchto ekosystémů dobře zapadaly, pokouší se nástroj py2many volat pomocné nástroje pro jejich výsledné naformátování. Konkrétně se v případě jazyka Rust jedná o nástroj rustfmt (lze nainstalovat samostatně) a v případě jazyka Go pak o nástroj go fmt (ten je součástí instalace samotného Go a není ho nutné instalovat samostatně).

Jen pro úplnost si ukažme instalaci nástroje rustfmt na operačním systému s podporou balíčků RPM. Je to snadné:

$ sudo dnf install rustfmt

Průběh instalace:

Last metadata expiration check: 3:36:59 ago on Fri 14 Jun 2024 05:53:53 AM CEST.
Dependencies resolved.
===============================================================================================================================================================
 Package                             Architecture                       Version                                      Repository                           Size
===============================================================================================================================================================
Installing:
 rustfmt                             x86_64                             1.78.0-1.fc38                                updates                             1.9 M
Installing dependencies:
 cargo                               x86_64                             1.78.0-1.fc38                                updates                             6.5 M
 
Transaction Summary
===============================================================================================================================================================
Install  2 Packages
 
Total download size: 8.4 M
Installed size: 26 M
Is this ok [y/N]: y
Downloading Packages:
(1/2): rustfmt-1.78.0-1.fc38.x86_64.rpm                                                                                        1.1 MB/s | 1.9 MB     00:01
(2/2): cargo-1.78.0-1.fc38.x86_64.rpm                                                                                          3.7 MB/s | 6.5 MB     00:01
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Total                                                                                                                          3.8 MB/s | 8.4 MB     00:02
Running transaction check
Transaction check succeeded.
Running transaction test
Transaction test succeeded.
Running transaction
  Preparing        :                                                                                                                                       1/1
  Installing       : cargo-1.78.0-1.fc38.x86_64                                                                                                            1/2
  Installing       : rustfmt-1.78.0-1.fc38.x86_64                                                                                                          2/2
  Running scriptlet: rustfmt-1.78.0-1.fc38.x86_64                                                                                                          2/2
  Verifying        : cargo-1.78.0-1.fc38.x86_64                                                                                                            1/2
  Verifying        : rustfmt-1.78.0-1.fc38.x86_64                                                                                                          2/2
 
Installed:
  cargo-1.78.0-1.fc38.x86_64                                                    rustfmt-1.78.0-1.fc38.x86_64

7. Transpřeklad programu typu „Hello, world!“

Začneme zdánlivě triviálním příkladem, a to konkrétně skriptem, který po svém spuštění vypíše obligátní pozdravení celému světu. V Pythonu je takový skript skutečně jednoduchý:

print("Hello, world!")

Už u takto jednoduchého programu však narazíme na to, že zdaleka ne všechny programovací jazyky (zejména ne ty klasické kompilované) podporují jednotlivé příkazy, které nejsou vloženy do funkce. Proto také výsledky transpřekladu dopadnou nevalně, protože mnohé výsledné zdrojové kódy nebudou přeložitelné nebo budou nespustitelné (s výjimkou skriptu transpřeloženého do jazyka Julia):

hello.cpp

#include <iostream> // NOLINT(build/include_order)
std::cout << std::string{"Hello, world!"};
std::cout << std::endl;
Poznámka: nekorektní program.

hello.go

package main
 
import (
"fmt")
 
 
 
fmt.Printf("%v\n","Hello, world!");
Poznámka: nekorektní program.

hello.jl

println(join(["Hello, world!"], " "));
Poznámka: korektní program, i když interně dosti zvláštně strukturovaný.

hello.rs

        //! ```cargo
        //! [package]
        //! edition = "2018"
        //! [dependencies]
        //!
        //! ```
 
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)]  // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)]  // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
 
 
 
 
println!("{}","Hello, world!");
Poznámka: nekorektní program.

8. Program obsahující pouze definici jediné funkce

Ve druhém demonstrační příkladu si otestujeme transpřeklad skriptu s definicí funkce bez parametrů i bez návratových hodnot. Tato funkce bude jen definována, ovšem nebude volána. Nejprve je vypsán původní zdrojový kód v Pythonu a poté zdrojové kódy získané po transpilaci do dalších programovacích jazyků:

hello_func2.py

def hello():
    print("Hello, world!")

hello_func2.cpp

#include <iostream> // NOLINT(build/include_order)
inline void hello() {
  std::cout << std::string{"Hello, world!"};
  std::cout << std::endl;
}

hello_func2.go

package main
 
import (
        "fmt"
)
 
func Hello() {
        fmt.Printf("%v\n", "Hello, world!")
}
Poznámka: poněkud zbytečné použití formátovacího řetězce.

hello_func2.jl

function hello()
    println(join(["Hello, world!"], " "));
end
 
Poznámka: pochopitelně lze zapsat jednodušším způsobem, ale opět se jedná o korektní program.

hello_func2.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
pub fn hello() {
    println!("{}", "Hello, world!");
}

Výsledky jsou v tomto případě korektní pro všechny jazyky, i když ne vždy odpovídají tomu, co by napsal člověk.

9. Definice funkce s voláním této funkce

Ve třetím demonstračním příkladu rozšíříme předchozí skript o přímé volání právě definované funkce. Opět zde narazíme na problémy v těch programovacích jazycích, v nichž není možné zapisovat příkazy mimo funkce či metody, což se v tomto případě týká všech jazyků kromě originálního Pythonu a Julie:

hello_func.py

def hello():
    print("Hello, world!")
 
 
hello()

hello_func.cpp

#include <iostream> // NOLINT(build/include_order)
inline void hello() {
  std::cout << std::string{"Hello, world!"};
  std::cout << std::endl;
}
 
hello();

hello_func.go

package main
 
import (
"fmt")
 
 
 
func Hello() {
fmt.Printf("%v\n","Hello, world!");}
 
 
Hello();

hello_func.jl

function hello()
    println(join(["Hello, world!"], " "));
end
 
hello();
Poznámka: podle očekávání korektní.

hello_func.rs

        //! ```cargo
        //! [package]
        //! edition = "2018"
        //! [dependencies]
        //!
        //! ```
 
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)]  // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)]  // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
 
 
 
 
pub fn hello()  {
println!("{}","Hello, world!");
 }
 
hello();

10. Výpočet faktoriálu realizovaný funkcí bez typových informací

Následuje příklad se složitější funkcí, konkrétně s rekurzivním výpočtem faktoriálu. Funkce je v programovacím jazyku Python zapsána bez použití typových informací (type hints). Výsledky transpilace nejsou zcela špatné (někdy je lze dokonce i přeložit a spustit :-), ovšem je evidentní, že chybějící typové informace nástroj py2many poměrně hodně zmátly:

factorial.py

def factorial(n):
    """Rekurzivní výpočet faktoriálu."""
    if n < 0:
        return None
    if n == 0:
        return 1
    result = n * factorial(n - 1)
    return result

factorial.cpp

template <typename T0> int factorial(T0 n) {
  if (n < 0) {
    return NULL;
  }
  if (n == 0) {
    return 1;
  }
  int result = n * (factorial(n - 1));
  return result;
}
Poznámka: zde se používají „divné“ typy, program kvůli tomu není korektní.

factorial.go

package main
 
 
 
 
func Factorial[T0 any](n T0 any) int {
if(n < 0) {
return nil
}
if(n == 0) {
return 1
}
var result int = (n*Factorial((n - 1)))
return result}
 
 
Poznámka: zápis typu je nekorektní, a to jak syntakticky, tak i sémanticky.

factorial.jl

function factorial{T0}(n::T0)::Int64
    if n < 0
        return nothing
    end
    if n == 0
        return 1
    end
    result = n*factorial(convert(, n - 1))
    return result
end
Poznámka: nelze spustit, prapodivné volání convert s nekorektní syntaxí.

factorial.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
pub fn factorial<T0>(n: T0) -> i32 {
    if (n as i32) < 0 {
        return None;
    }
    if (n as i32) == 0 {
        return 1;
    }
    let result: i32 = ((n as i32) * factorial(((n as i32) - 1)));
    return result;
}
Poznámka: zde opět dochází k testu typu předávané hodnoty, což není zcela ideální řešení.

11. Ackermannova funkce definovaná bez použití datových typů

I další demonstrační příklad, který si v dnešním článku ukážeme, obsahuje definice funkcí. Konkrétně se jedná o známou Ackermannovu funkci, kterou v Pythonu pochopitelně můžeme definovat bez toho, abychom uvedli typové informace o jejích parametrech i o návratové hodnotě. V navazující kapitole si pak ukážeme tutéž funkci, ovšem s uvedením typových informací.

ackermann_untyped.py

# Výpočet Ackermannovy funkce, založeno na konstrukci if
 
def A(m, n):
    """Ackermannova funkce."""
    if m == 0:
        return n + 1
    if n == 0:
        return A(m - 1, 1)
    return A(m - 1, A(m, n - 1))
 
 
def check_a():
    """Korektnosti výpočtu Ackermannovy funkce."""
    for m in range(4):
        for n in range(5):
            print(m, n, A(m, n))
 

ackermann_untyped.cpp

#include <cppitertools/range.hpp> // NOLINT(build/include_order)
#include <iostream>               // NOLINT(build/include_order)
template <typename T0, typename T1> int A(T0 m, T1 n) {
  if (m == 0) {
    return n + 1;
  }
  if (n == 0) {
    return A(m - 1, 1);
  }
  return A(m - 1, A(m, n - 1));
}
 
inline void check_a() {
  for (auto m : iter::range(4)) {
    for (auto n : iter::range(5)) {
      std::cout << m;
      std::cout << " ";
      std::cout << n;
      std::cout << " ";
      std::cout << A(m, n);
      std::cout << std::endl;
    }
  }
}
Poznámka: ve skutečnosti je tato varianta prakticky stejně obecná jako varianta v Pythonu, tj. nejsme zde omezeni pouze na datový typ int.

ackermann_untyped.go

package main
 
import (
iter "github.com/hgfischer/go-iter"
"fmt")
 
 
 
func A[T0 any, T1 any](m T0 any, n T1 any) int {
if(m == 0) {
return (n + 1)
}
if(n == 0) {
return A((m - 1), 1)
}
return A((m - 1), A(m, (n - 1)))}
 
 
func CheckA() {
for _, m := range iter.NewIntSeq(iter.Start(0), iter.Stop(4)).All() {
for _, n := range iter.NewIntSeq(iter.Start(0), iter.Stop(5)).All() {
fmt.Printf("%v %v %v\n",m, n, A(m, n));
}
}}
 
 
Poznámka: jedná se o nekorektní variantu, a to jak z hlediska syntaxe, tak i sémantiky. Ovšem zajímavě je řešena iterace přes celočíselné hodnoty.

ackermann_untyped.jl

function A{T0, T1}(m::T0, n::T1)::Int64
    if m == 0
        return n + 1
    end
    if n == 0
        return A(convert(, m - 1), convert(, 1))
    end
    return A(convert(, m - 1), convert(, A(m, convert(, n - 1))))
end
 
function check_a()
    for m in 0:4 - 1
        for n in 0:5 - 1
            println(join([m, n, A(m, n)], " "));
        end
    end
end
 
Poznámka: varianta naprogramovaná v jazyce Julia opět vychází vlastně nejlépe, i když i kde vidíme volání convert, které nebude interpretováno (podle očekávání).

ackermann_untyped.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
pub fn A<T0, T1>(m: T0, n: T1) -> i32 {
    if (m as i32) == 0 {
        return ((n as i32) + 1);
    }
    if (n as i32) == 0 {
        return A(((m as i32) - 1), 1);
    }
    return A(((m as i32) - 1), A(m, ((n as i32) - 1)));
}
 
pub fn check_a() {
    for m in (0..4) {
        for n in (0..5) {
            println!("{} {} {}", m, n, A(m, n));
        }
    }
}
Poznámka: dobře se přeložila zejména konstrukce for-range, hůře už (podle očekávání) volání funkce, u které nejsou dopředu známé datové typy parametrů.

12. Ackermannova funkce definovaná s využitím typových informací

Pokusme se tedy tranpřekladači pomoci a upravit Ackermannovu funkci takovým způsobem, aby byly již v čase (trans)překladu známé jak typy parametrů této funkce, tak i typ návratové hodnoty:

ackermann_typed.py

# Výpočet Ackermannovy funkce, založeno na konstrukci if
 
def A(m: int, n: int) -> int:
    """Ackermannova funkce."""
    if m == 0:
        return n + 1
    if n == 0:
        return A(m - 1, 1)
    return A(m - 1, A(m, n - 1))
 
 
def check_a() -> None:
    """Korektnosti výpočtu Ackermannovy funkce."""
    for m in range(4):
        for n in range(5):
            print(m, n, A(m, n))
 

ackermann_typed.cpp

#include <cppitertools/range.hpp> // NOLINT(build/include_order)
#include <iostream>               // NOLINT(build/include_order)
inline int A(int m, int n) {
  if (m == 0) {
    return n + 1;
  }
  if (n == 0) {
    return A(m - 1, 1);
  }
  return A(m - 1, A(m, n - 1));
}
 
inline auto check_a() {
  for (auto m : iter::range(4)) {
    for (auto n : iter::range(5)) {
      std::cout << m;
      std::cout << " ";
      std::cout << n;
      std::cout << " ";
      std::cout << A(m, n);
      std::cout << std::endl;
    }
  }
}
Poznámka: zde evidentně typové informace velmi pomohly.

ackermann_typed.go

package main
 
import (
        "fmt"
        iter "github.com/hgfischer/go-iter"
)
 
func A(m int, n int) int {
        if m == 0 {
                return (n + 1)
        }
        if n == 0 {
                return A((m - 1), 1)
        }
        return A((m - 1), A(m, (n-1)))
}
 
func CheckA() {
        for _, m := range iter.NewIntSeq(iter.Start(0), iter.Stop(4)).All() {
                for _, n := range iter.NewIntSeq(iter.Start(0), iter.Stop(5)).All() {
                        fmt.Printf("%v %v %v\n", m, n, A(m, n))
                }
        }
}
Poznámka: až na dosti prapodivnou realizaci iterátorů se vlastně jedná o korektní přístup a samotná Ackermannova funkce je v pořádku.

ackermann_typed.jl

function A(m::Int64, n::Int64)::Int64
    if m == 0
        return n + 1
    end
    if n == 0
        return A(m - 1, 1)
    end
    return A(m - 1, A(m, n - 1))
end
 
function check_a()::
    for m in 0:4 - 1
        for n in 0:5 - 1
            println(join([m, n, A(m, n)], " "));
        end
    end
end
 
Poznámka: zde již do určité míry vidíme důvod, proč se výsledná zpráva skládá pomocí join (i když se nejedná o nejkrásnější řešení).

ackermann_typed.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
pub fn A(m: i32, n: i32) -> i32 {
    if m == 0 {
        return (n + 1);
    }
    if n == 0 {
        return A((m - 1), 1);
    }
    return A((m - 1), A(m, (n - 1)));
}
 
pub fn check_a() {
    for m in (0..4) {
        for n in (0..5) {
            println!("{} {} {}", m, n, A(m, n));
        }
    }
}
Poznámka: v pořádku :-)

13. Funkce s implementací algoritmu bublinkového řazení

Další zdrojový soubor naprogramovaný v Pythonu, který si dnes ukážeme, obsahuje funkci nazvanou bubble_sort s realizací algoritmu bublinkového řazení. V této funkci se tedy používají operace se seznamem, s nímž se vlastně pracuje takovým způsobem, jakoby se jednalo o pole s neměnnou délkou (počtem prvků). Samotný algoritmus je realizován dvojicí vnořených smyček a podmínkou. Povšimněte si taktéž „dvojitého přiřazení“ do prvků pole s indexy j a j + 1 (tím je realizována operace prohození prvků bez použití třetí pomocné proměnné):

bubble.py

def bubble_sort(size):
    a = [random.randrange(0, 10000) for i in range(size)]
 
    for i in range(size - 1, 0, -1):
        for j in range(0, i):
            if a[j] > a[j + 1]:
                a[j], a[j + 1] = a[j + 1], a[j]
 
    print(a)
Poznámka: jedná se o velmi neefektivní algoritmus, který je vhodný jen pro malá pole/seznamy (řekněme do pěti prvků).

bubble.cpp

FAILED
Poznámka: zde evidentně překlad naprosto selhal.

bubble.go

package main
 
import (
"fmt"
iter "github.com/hgfischer/go-iter")
 
 
 
func BubbleSort[T0 any](size T0 any) {
a := iter.NewIntSeq(iter.Start(0), iter.Stop(size)).All().iter().map(|i| randrange(random, 0, 10000)).collect::<Vec<_>>()
for _, i := range iter.NewIntSeq(iter.Start((size - 1)), iter.Stop(0), iter.Step(-1)).All() {
for _, j := range iter.NewIntSeq(iter.Start(0), iter.Stop(i)).All() {
if(a[j] > a[(j + 1)]) {
{
var __tmp1, __tmp2 = a[(j + 1)], a[j]
a[j] = __tmp1
a[(j + 1)] = __tmp2
}
}
}
}
fmt.Printf("%v\n",a);}
Poznámka: opět se jedná o syntakticky i sémanticky nekorektní program, takže není divu, že ani go fmt nedokázal zdrojový kód naformátovat.

bubble.jl

function bubble_sort{T0}(size::T0)
    a = [randrange(random, 0, 10000) for i in 0:size - 1]
    for i in 0 - 1:-1:size - 1
        for j in 0:i - 1
            if a[j] > a[j + 1]
                a[j], a[j + 1] = (a[j + 1], a[j])
            end
        end
    end
    println(join([a], " "));
end
Poznámka: toto je již mnohem lepší řešení.

bubble.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
pub fn bubble_sort<T0>(size: T0) {
    let mut a = (0..size)
        .map(|i| random.randrange(0, 10000))
        .collect::<Vec<_>>();
    for i in (((size as i32) - 1)..0).step_by(-1) {
        for j in (0..i) {
            if a[j] > a[((j as i32) + 1)] {
                ({
                    let (__tmp1, __tmp2) = (a[((j as i32) + 1)], a[j]);
                    a[j] = __tmp1;
                    a[((j as i32) + 1)] = __tmp2;
                });
            }
        }
    }
    println!("{}", a);
}
Poznámka: i zde by se našlo mnoho neidiomatických konstrukcí, ovšem výsledek je mnohem lepší, než v případě C++ (selhání) a Go (transpilace proběhla, ale s chybným výsledkem).

14. Datové typy v programovacím jazyce Python i v jazycích, do nichž je transpilován

V reálných programech vytvořených v jazyku Python se prakticky vždy setkáme s využitím nějakých typů sekvencí, popř. kontejnerů, kam spadají datové typy seznam (list), n-tice (tuple), množiny (set) a slovníky (dictionary). Ostatně s vytvořením a inicializací seznamu jsme se již setkali v předchozí kapitole při konstrukci seznamu s náhodnými hodnotami. Otázkou ovšem zůstává, jakým způsobem jsou operace s těmito datovými typy transpilovány, protože zde opět narazíme především na sémantické rozdíly, mnohdy zcela odlišné typové systémy apod. Dnes si ukážeme dva základní příklady z této oblasti a v navazujícím článku na toto téma pochopitelně ještě navážeme, protože je pro reálné použití py2many velmi důležité.

15. Základní operace se seznamy: varianta s datovými typy i bez typů

V dalších dvou kapitolách budou ukázány výsledky transpilace dvou skriptů, které obsahují funkci pro konstrukci a naplnění seznamu sekvencí celočíselných hodnot. První z těchto skriptů neobsahuje typové informace:

list_untyped.py

def fill_in_list(size):
    l = []
    for i in range(size):
        l.append(i+1)
    return l

Druhý skript obsahuje totožný kód, nyní však s typovými informacemi:

list_typed.py

def fill_in_list(size: int) -> list[int]:
    l = []
    for i in range(size):
        l.append(i+1)
    return l

16. Výsledek transpilace kódu, v němž nebyly použity typové informace

Výsledky transpilace skriptu, v němž se konstruuje seznam ve skriptu bez typových informací, nedopadne ani v jednom případě dobře:

bitcoin_skoleni

list_untyped.cpp

#include <cppitertools/range.hpp> // NOLINT(build/include_order)
#include <vector>                 // NOLINT(build/include_order)
template <typename T0> List fill_in_list(T0 size) {
  std::vector<
      decltype(std::declval<typename decltype(range(size))::value_type>() + 1)>
      l = {};
  for (auto i : iter::range(size)) {
    l.push_back(i + 1);
  }
  return l;
}
Poznámka: paradoxně je toto řešen asi nejblíže očekávanému výsledku.

list_untyped.go

package main
 
import (
iter "github.com/hgfischer/go-iter")
 
 
 
func FillInList[T0 any](size T0 any) List {
var l List = []None{}
for _, i := range iter.NewIntSeq(iter.Start(0), iter.Stop(size)).All() {
l = append(l, (i + 1));
}
return l}
 
 
Poznámka: opět nekorektní definice typu už v hlavičce funkce.

list_untyped.jl

function fill_in_list{T0}(size::T0)::List
    l = []
    for i in 0:size - 1
        push!(l, i + 1);
    end
    return l
end
 
Poznámka: po malých úpravách lze použít.

list_untyped.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
use std::collections;
 
pub fn fill_in_list<T0>(size: T0) -> List {
    let mut l: List = vec![];
    for i in (0..size) {
        l.push(((i as i32) + 1));
    }
    return l;
}
Poznámka: až na nekorektní pokusy o přetypování se opět jedná o celkem vhodné řešení, vyžaduje však ruční zásahy.

17. Výsledek transpilace kódu, v němž byly použity typové informace

list_typed.cpp

#include <cppitertools/range.hpp> // NOLINT(build/include_order)
#include <vector>                 // NOLINT(build/include_order)
inline auto fill_in_list(int size) {
  std::vector<
      decltype(std::declval<typename decltype(range(size))::value_type>() + 1)>
      l = {};
  for (auto i : iter::range(size)) {
    l.push_back(i + 1);
  }
  return l;
}
Poznámka: vyžaduje externí knihovnu s iterátorem, trošku nešťastná šablona, jinak celkem v pořádku.

list_typed.go

package main
 
import (
    iter "github.com/hgfischer/go-iter"
)
 
func FillInList(size int) None {
    var l List = []None{}
    for _, i := range iter.NewIntSeq(iter.Start(0), iter.Stop(size)).All() {
        l = append(l, (i + 1))
    }
    return None(l)
}
Poznámka: divný návratový typ a tím pádem i typ seznamu l.

list_typed.jl

function fill_in_list(size::Int64)::
    l = []
    for i in 0:size - 1
        push!(l, i + 1);
    end
    return l
end
Poznámka: syntaktické chyby, jinak vlastně korektní řešení.

list_typed.rs

//! ```cargo
//! [package]
//! edition = "2018"
//! [dependencies]
//!
//! ```
 
#![allow(clippy::collapsible_else_if)]
#![allow(clippy::double_parens)] // https://github.com/adsharma/py2many/issues/17
#![allow(clippy::map_identity)]
#![allow(clippy::needless_return)]
#![allow(clippy::print_literal)]
#![allow(clippy::ptr_arg)]
#![allow(clippy::redundant_static_lifetimes)] // https://github.com/adsharma/py2many/issues/266
#![allow(clippy::unnecessary_cast)]
#![allow(clippy::upper_case_acronyms)]
#![allow(clippy::useless_vec)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(non_upper_case_globals)]
#![allow(unused_imports)]
#![allow(unused_mut)]
#![allow(unused_parens)]
 
use std::collections;
 
pub fn fill_in_list(size: i32) {
    let mut l: List = vec![];
    for i in (0..size) {
        l.push(((i as i32) + 1));
    }
    return l as _;
}
Poznámka: typ List není definován, jinak v pořádku.

18. Tabulka se srovnáním úspěchu transpřekladu jednotlivých příkladů

Výsledky projektu py2many jsou prozatím dosti špatné, jak je to ostatně patrné z následující tabulky. Hodnoty × a ✓ mají zřejmý význam, hodnota 1/2 pak představuje řešení, které sice není přímo přeložitelné a spustitelné, ale není zcela špatné – malým ručním zásahem je možné transpilované zdrojové kódy opravit:

Program Testuje se C++ Go Julia Rust
hello.py jednotlivý příkaz mimo funkci × × ×
hello_func2.py definice samostatné funkce
hello_func.py definice funkce s jejím voláním × × ×
factorial.py definice funkce bez typových informací × × × ×
ackermann_untyped.py Ackermannova funkce definovaná bez datových typů × 1/2 ?
ackermann_typed.py Ackermannova funkce definovaná s datovými typy 1/2
bubble.py realizace algoritmu bublinkového řazení × × 1/2 1/2
list_untyped.py konstrukce a naplnění seznamu; bez typů 1/2 × 1/2 1/2
list_typed.py konstrukce a naplnění seznamu; s typy 1/2 1/2 1/2 1/2
Poznámka: příště se zaměříme na nepatrně složitější konstrukce Pythonu, na nichž si opět ověříme vhodnost či nevhodnost py2many pro reálné použití.

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 Python a pro nástroj py2many 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.py jednotlivý příkaz volaný mimo funkci nebo metodu https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello.py
2 hello.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello.cpp
3 hello.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello.go
4 hello.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello.jl
5 hello.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello.rs
       
6 hello_func2.py definice samostatné funkce bez jejího volání https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func2.py
7 hello_func2.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func2.cpp
8 hello_func2.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func2.go
9 hello_func2.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func2.jl
10 hello_func2.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func2.rs
       
11 hello_func.py definice funkce s jejím voláním https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello_func.py
12 hello_func.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/he­llo_func.cpp
13 hello_func.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello_func.go
14 hello_func.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello_func.jl
15 hello_func.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/hello_func.rs
       
16 factorial.py definice složitější funkce bez typových informací https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/factorial.py
17 factorial.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/factorial.cpp
18 factorial.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/factorial.go
19 factorial.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/factorial.jl
20 factorial.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/factorial.rs
       
21 ackermann_untyped.py Ackermannova funkce definovaná bez datových typů (hintů) https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_untyped.py
22 ackermann_untyped.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_untyped.cpp
23 ackermann_untyped.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_untyped.go
24 ackermann_untyped.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_untyped.jl
25 ackermann_untyped.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_untyped.rs
       
26 ackermann_typed.py Ackermannova funkce definovaná s datovými typy (hinty) https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_typed.py
27 ackermann_typed.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_typed.cpp
28 ackermann_typed.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_typed.go
29 ackermann_typed.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_typed.jl
30 ackermann_typed.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/ac­kermann_typed.rs
       
31 bubble.py algoritmus bublinkového řazení https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/bubble.py
32 bubble.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/bubble.cpp
33 bubble.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/bubble.go
34 bubble.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/bubble.jl
35 bubble.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/bubble.rs
       
36 list_untyped.py práce se seznamy, bez typových informací (hintů) https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_untyped.py
37 list_untyped.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_untyped.cpp
38 list_untyped.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_untyped.go
39 list_untyped.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_untyped.jl
40 list_untyped.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_untyped.rs
       
41 list_typed.py práce se seznamy, s typovými informacemi (hinty) https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/list_typed.py
42 list_typed.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/lis­t_typed.cpp
43 list_typed.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/list_typed.go
44 list_typed.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/list_typed.jl
45 list_typed.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/list_typed.rs
       
46 async_await.py použití jazykových konstrukcí async a await https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/a­sync_await.py
47 async_await.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/a­sync_await.cpp
48 async_await.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/a­sync_await.go
49 async_await.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/a­sync_await.jl
50 async_await.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/a­sync_await.rs
       
51 safe_div.py realizace funkce pro podíl dvou hodnot s detekcí dělení nulou https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/safe_div.py
52 safe_div.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/safe_div.cpp
53 safe_div.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/safe_div.go
54 safe_div.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/safe_div.jl
55 safe_div.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/safe_div.rs
       
56 visitor.py jednoduchá třída s několika metodami https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/visitor.py
57 visitor.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/visitor.cpp
58 visitor.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/visitor.go
59 visitor.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/visitor.jl
60 visitor.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/visitor.rs
       
61 pattern_matching_factorial.py pattern matching použitý při výpočtu faktoriálu https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/pat­tern_matching_factorial.py
62 pattern_matching_factorial.cpp výsledek transpřekladu do jazyka C++ https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/pat­tern_matching_factorial.cpp
63 pattern_matching_factorial.go výsledek transpřekladu do jazyka Go https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/pat­tern_matching_factorial.go
64 pattern_matching_factorial.jl výsledek transpřekladu do jazyka Julia https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/pat­tern_matching_factorial.jl
65 pattern_matching_factorial.rs výsledek transpřekladu do jazyka Rust https://github.com/tisnik/most-popular-python-libs/blob/master/py2many/pat­tern_matching_factorial.rs

20. Odkazy na Internetu

  1. py2many na GitHubu
    https://github.com/py2many/py2many
  2. py2many na PyPi
    https://pypi.org/project/py2many/
  3. Awesome Transpilers
    https://github.com/milahu/awesome-transpilers
  4. Pseudocode (Wikipedia)
    https://en.wikipedia.org/wi­ki/Pseudocode
  5. Pseudokód (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Pseudok%C3%B3d
  6. Cython (home page)
    http://cython.org/
  7. Cython (wiki)
    https://github.com/cython/cython/wiki
  8. Cython (Wikipedia)
    https://en.wikipedia.org/wiki/Cython
  9. Cython (GitHub)
    https://github.com/cython/cython
  10. Seriál Programovací jazyk Julia
    https://www.root.cz/seria­ly/programovaci-jazyk-julia/
  11. Seriál programovací jazyk Rust
    https://www.root.cz/seria­ly/programovaci-jazyk-rust/
  12. Ackermann function
    https://en.wikipedia.org/wi­ki/Ackermann_function
  13. EmbeddingCython
    https://github.com/cython/cyt­hon/wiki/EmbeddingCython
  14. The Basics of Cython
    http://docs.cython.org/en/la­test/src/tutorial/cython_tu­torial.html
  15. Compiling to WebAssembly: It’s Happening!
    https://hacks.mozilla.org/2015/12/com­piling-to-webassembly-its-happening/
  16. WebAssembly
    https://webassembly.org/
  17. A quick guide about Python implementations
    https://blog.rmotr.com/a-quick-guide-about-python-implementations-aa224109f321
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.

Autor článku

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