MojoはPythonのスーパーセットを目指している高速に動作する言語らしいです。
ここを見ると、インストールできます。
https://dev.to/jjokah/getting-started-with-mojo-4985
WSL2ならスムーズにインストールできます。
インストールできたら、Project Euler 1を解いてみましょう。
https://projecteuler.net/problem=1
Pythonならこんな風に書くでしょうか。
import sys def f(N: int) -> int: return sum(n for n in range(1, N) if n % 3 == 0 or n % 5 == 0) N = int(sys.argv[1]) print(f(N))
しかし、MojoではGenerator式とか内包表記とかはまだ書けません。なので、手続型で書くと、
# e001.py import sys def f(N: int) -> int: s = 0 for n in range(1, N): if n % 3 == 0 or n % 5 == 0: s += n return s N = int(sys.argv[1]) print(f(N))
これをMojoにすると、
# e001.mojo import sys fn f(N: Int) -> Int: var s = 0 for n in range(1, N): if n % 3 == 0 or n % 5 == 0: s += n return s fn main(): let args = sys.argv() try: let N = atol(args[1]) print(f(N)) except: pass
まず、明確にmainがあって、関数はdefも使えるらしいですが、fnで宣言します。
変数もvarかletで宣言して、letならimmutableです。
型はintでなくてIntで、これは64ビット符号付き整数のようです。
早速、速度を測ってみましょう。
Pythonは3.8.8、PyPyは3.1.17、Mojoは0.4.0です。
$ time python e001.py 1000000000 233333333166666668 real 1m3.780s user 1m3.770s sys 0m0.000s $ time pypy3 e001.py 1000000000 233333333166666668 real 0m2.679s user 0m2.650s sys 0m0.020s $ time mojo e001.mojo 1000000000 233333333166666668 real 0m1.122s user 0m1.124s sys 0m0.010s
確かに速いのですが、こういう単純なコードだとPyPyも速いんですよね。
Mojoは実行ファイルも作ることができるのでそちらも試してみましょう。
mojo build e001.mojo -o e001_mojo time ./e001_mojo 1000000000 233333333166666668 real 0m1.067s user 0m1.053s sys 0m0.010s
変わらないですね。
C++とRustでも試してみましょう。
g++は9.4.0、rustcは1.72.0です。
g++ -O2 e001.cpp -o e001_cpp time ./e001_cpp 1000000000 233333333166666668 real 0m0.839s user 0m0.836s sys 0m0.000s rustc -C opt-level=3 e001.rs -o e001_rust time ./e001_rust 1000000000 233333333166666668 real 0m2.207s user 0m2.185s sys 0m0.010s
C++はさすがの速さなのですが、Rustはなぜ遅いんでしょうね。
// e001.cpp #include <iostream> typedef long long ll; ll f(ll N) { ll s = 0; for(ll n = 1; n < N; ++n) { if(n % 3 == 0 || n % 5 == 0) s += n; } return s; } int main(int argc, char **argv) { const ll N = atoll(argv[1]); std::cout << f(N) << std::endl; }
// e001.rs #![allow(non_snake_case)] use std::env; fn f(N: u64) -> u64 { let mut s: u64 = 0; for n in 1..N { if n % 3 == 0 || n % 5 == 0 { s += n } } s } fn main() { let args: Vec<String> = env::args().collect(); let N: u64 = args[1].parse().unwrap(); println!("{}", f(N)) }