見出し画像

Mojo入門 (2) - Mojo言語の基本

以下の記事が面白かったので、かるくまとめました。

Mojo language basics

前回


1. Mojo言語の基本

Mojo」は、「Rust」「C++」などの他のシステム言語と多くの共通点がありますが、「Pythonのスーパーセット」になるよう設計されているため、「Python」の機能や概念の多くは、「Mojo」にうまく反映されています。

(1) Pythonパッケージからコードをインポートして実行することが可能。
(2) Pythonと同様に REPL や Jupyte Notebook でトップレベルでのコード実行が可能。

ただし、「Mojo」は新しい言語であり、Pythonの新実装ではありません。「Mojo」は、システムプログラミング機能強力な型チェックメモリ安全性次世代コンパイラなどを備え、Pythonをまったく新しいレベルに引き上げます。

2. Mojoプログラム

「Mojo」はコンパイル言語であり、パフォーマンスとメモリ安全性の多くはこの事実から派生しています。

「Mojoプログラム」 (.mojo または .🔥 ファイル) は、AOT (ahead-of-time) または JIT (just-in-time) でコンパイルできます。他のコンパイル言語と同様、プログラムへのエントリポイントとして fn main() が必要です。

fn main():
    var x: Int = 1
    x += 1
    print(x)


Pythonと同様の def main() も利用できますが、fn main() を使用すると動作が少し異なります。「Mojoプログラム」ではなく「Mojoモジュール」 (APIライブラリ) では、インポートするため、main() は必要ありません。

3. 構文とセマンティクス

「Mojo」は Pythonの構文とセマンティクスをすべてサポートしています。ただし、「Mojo」はまだ開発中であるため、Pythonの機能のうち、「Mojo」にまだ実装されていないものがいくつかあります (詳しくは「Mojo roadmap」を参照)。不足している Python機能はすべて間もなく提供される予定です。

さらに、「Mojo」にはPython機能を超える多くの機能が含まれています。

4. 関数

Mojoの関数は、fn (上記) または def (Python と同様) で定義します。fnは、厳密に型指定されたメモリセーフな動作を強制するのに対し、def は Pythonスタイルの動的を提供します。

fn と def にはそれぞれの価値があるため、両方学習することが重要です (詳しくは「programming manual」を参照)。

5. 変数

Mojoの変数は、var で可変値、または let で不変値を定義します。

fn do_math():
    let x: Int = 1
    let y = 2
    print(x + y)

do_math()
3

6. 関数の引数と戻り値

関数 fn の引数と戻り値には、型が必要です。

引数を不変 (borrowed) にしたい場合は、引数の頭に borrowed を指定、または何も指定しない (デフォルト) ようにします。

fn add(x: Int, y: Int) -> Int:
    return x + y

z = add(1, 2)
print(z)
3

引数を可変 (inout) にしたい場合は、引数の頭に inout を指定します。この引数は、関数内で変更でき、その変更が関数外に反映されます。

fn add_inout(inout x: Int, inout y: Int) -> Int:
    x += 1
    y += 1
    return x + y

var a = 1
var b = 2
c = add_inout(a, b)
print(a)
print(b)
print(c)
2
3
5

引数を所有者 (owned) にしたい場合は、引数の頭に owned を指定します。この引数は、関数内で変更できますが、その変更は関数外に反映されません。

fn set_fire(owned text: String) -> String:
    text += "🔥"
    return text

fn mojo():
    let a: String = "mojo"
    let b = set_fire(a)
    print(a)
    print(b)

mojo()
mojo
mojo🔥

ただし、関数に値の所有権を与え、コピーを作成したくない場合 (型によってはコストのかかる操作になる可能性がある)、関数にaを渡すときに ^ “transfer” 演算子を指定できます。 transfer 演算子は事実上、ローカル変数名を破壊します。後でそれを呼び出そうとすると、コンパイラエラーが発生します。

   let b = set_fire(a^)

【注意】現在、Mojo は関数が値を返すときに常にコピーを作成します。

7. 構造体

Mojoの構造体は、Pythonのクラスに似ています。どちらもメソッド、フィールド、演算子のオーバーロード、メタプログラミング用のデコレータなどをサポートしています。ただし、Mojoの構造体は完全に静的であり、コンパイル時にバインドされます。動的なものは許可されません。

構造体の例は、次のとおりです。

struct MyPair:
    var first: Int
    var second: Int

    fn __init__(inout self, first: Int, second: Int):
        self.first = first
        self.second = second
    
    fn dump(self):
        print(self.first, self.second)

使用方法は、次のとおりです。

let mine = MyPair(2, 4)
mine.dump()
2 4

8. Pythonのインテグレーション

Mojoはまだ開発中であり、Pythonの完全なスーパーセットではありませんが、既存のPythonコードをすぐに活用できます。内部ではCPythonインタープリタを使用してPythonコードを実行します。

NumPyをインポートして使用する例は、次のとおりです。Pythonのnumpy はインストールされている必要があります。

from python import Python

let np = Python.import_module("numpy")

ar = np.arange(15).reshape(3, 5)
print(ar)
print(ar.shape)
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
(3, 5)

【注意】Mojoをインストールすると、インストーラはMojoで使用する Pythonのバージョンをシステムで検索し、そのパスを modular.cfg に追加します。 MOJO_PYTHON_LIBRARY 環境変数で、MojoのPythonライブラリへのパスをオーバーライドすることができます。

次回



この記事が気に入ったらサポートをしてみませんか?