新進気鋭のプログラミング言語であるMoonBit。
その公式のチュートリアルを翻訳し、大事なところだけをまとめた記事です。
元のページは以下です。
https://docs.moonbitlang.com/en/latest/tutorial/tour.html
インストール方法(VSCode)
- MoonBitはVSCodeの拡張機能としても提供されています。VSCodeマーケットプレイスからインストールしてください。
- この拡張機能を使えば、VSCode上で「Install moonbit toolchain」コマンドを実行することで、MoonBitがOSにインストールされます。

インストール方法(コマンド)
- VSCodeを使わなくとも、コマンドでのインストールが可能です。
- MacやLinuxユーザーの場合は以下のコマンドです。
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash - Windowsの場合は以下のコマンドです。
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.com/install/powershell.ps1 | iex - MoonBitは、
$HOME/.moonにインストールされ、パスも設定されます。 - バージョンアップも同じコマンドで可能です。
MoonBitのプロジェクトを作成する
-
moon new <path>で新しいプロジェクトを作成します。今回は例として、moon new examineとします。examine ├── Agents.md ├── cmd │ └── main │ ├── main.mbt │ └── moon.pkg.json ├── LICENSE ├── moon.mod.json ├── moon.pkg.json ├── my_project_test.mbt ├── my_project.mbt ├── README.mbt.md └── README.md -> README.mbt.md -
cd my_project && moon run cmd/mainと実行してみてください。最小構成のサンプルプログラムが動きます。
「合格者はだれ?」を作ってみよう
宣言
- この例では、何人かの生徒の得点から、何人の生徒がテストに合格したかを算出するプログラムを作ってみます。
- プロジェクトルートの
./top.mbtに以下のコードを書いていきます。cmd配下やcmd/main配下ではありません。 - まずはstructを使って学生IDとスコアを含む構造体を宣言します。
struct Student { id : String score : Double } - enumを使って、合格・不合格を列挙型で表現します。
enum ExamResult { Pass Fail } - 生徒が合格しているかどうかを判定する関数を作成します。
fn is_qualified(student : Student, criteria: Double) -> ExamResult { ... } - この関数は、生徒と基準(何点以上を合格とするか)を受け取り、ExamResultを返します。
-
...と書くことで、未実装のままにしていられます。Pythonのpassと違って、このまま動かすとエラーになります。 - 次に、何人の生徒が合格したかを数える関数を作成します。
fn count_qualified_students( students : Array[Student], is_qualified : (Student) -> ExamResult ) -> Int { ... } - MoonBitでは、関数を引数や戻り値で使用できます。
- この関数は、生徒の配列と、合格判定関数を受け取り、合格者数を返します。
テストコード
- 次に、テストコードを書きます
test "is qualified" { assert_eq(is_qualified(Student::{ id : "0", score : 50.0 }, 60.0), Fail) assert_eq(is_qualified(Student::{ id : "1", score : 60.0 }, 60.0), Pass) assert_eq(is_qualified(Student::{ id : "2", score : 13.0 }, 7.0), Pass) } - 基準が60点の時に50点の生徒は不合格など、3つのケースをテストしています。
- しかしこれはエラーになります。原因は
assert_eqにあります。 -
assert_eqを使って比較をするためには、構造体にEqトレイトとShowトレイトを実装している必要があるからです。fn assert_eq -> Unit { ... } -
Eqでは、値同士をどのように比較するかを定義します。 -
Showでは、値をStringに変換する方法を定義します。assert_eqは、一致しない時に期待値と実際の値を表示するために使用します。 - これらのトレイトを実装する方法は2つあります。
-
Eqは「明示的な実装」をします。impl Eq for ExamResult with op_equal(self, other) { match (self, other) { (Pass, Pass) | (Fail, Fail) => true _ => false } } -
Showは「deriveで実装」します。enum ExamResult { Pass Fail } derive(Show) - トレイトの実装は完了です。それでは次のテストコードを書きましょう。
test "count qualified students" { let students = [ { id: "0", score: 10.0 }, { id: "1", score: 50.0 }, { id: "2", score: 61.0 }, ] let criteria1 = fn(student) { is_qualified(student, 10) } let criteria2 = fn(student) { is_qualified(student, 50) } assert_eq(count_qualified_students(students, criteria1), 3) assert_eq(count_qualified_students(students, criteria2), 2) } - 3人の生徒の配列を作成し、2つの基準で合格者数を数えています。
- ここでは、ラムダ式を使用して、以前に定義した
is_qualifiedを再利用し、異なる基準値で合格者数のカウントすることを実現しています。
関数の実装
- いよいよ、関数の中身を実装していきます。
fn is_qualified(student : Student, criteria : Double) -> ExamResult { if student.score >= criteria { Pass } else { Fail } } - MoonBitでは、最後の式の結果が関数の戻り値となり、ここでは
if式の値が返ることになります。 -
count_qualified_students関数では、配列を処理するため、ループを行います。 - まずは敢えて非効率な書き方で実装します。
fn count_qualified_students( students : Array[Student], is_qualified : (Student) -> ExamResult ) -> Int { let mut count = 0 for i = 0; i < students.length(); i = i + 1 { if is_qualified(students[i]) == Pass { count += 1 } } count } - これは、次のように書き換えられます。
fn count_qualified_students( students : Array[Student], is_qualified : (Student) -> ExamResult ) -> Int { let mut count = 0 for student in students { if is_qualified(student) == Pass { count += 1} } count } - さらに短くすることも可能です。
fn count_qualified_students( students : Array[Student], is_qualified : (Student) -> ExamResult ) -> Int { students.iter().filter(fn(student) { is_qualified(student) == Pass }).count() }
ライブラリを作る
- これで実装は完了です!初めてのMoonBitプログラム、おめでとうございます!
-
moon testコマンドを実行して、すべてのテストが通ります。 - それではここまでのコードをライブラリとして提供してみましょう。
可視性を調整する
- 上で定義したテストブロックを新しいファイル
./top_test.mbtに移動してみましょう。 - すると次のようなエラーが表示されてしまいます。
-
is_qualifiedとcount_qualified_studentsが存在しません。 -
FailとPassが未定義です。 -
Studentは構造体型ではなく、フィールドidが見つかりません。など。
-
- これらはすべて可視性の問題から生じています。
- 外部からアクセスできるようにするには、関数は
pub、構造体や列挙型はpub(all)キーワードを使用します。- struct Student { + pub(all) struct Student { ... - enum ExamResult { + pub(all) enum ExamResult { ... - fn is_qualified(student: Student, criteria: Double) -> ExamResult { + pub fn is_qualified(student: Student, criteria: Double) -> ExamResult { ... - fn count_qualified_students( + pub fn count_qualified_students( ... - impl Eq for ExamResult with equal(self, other) { + pub impl Eq for ExamResult with equal(self, other) { ... - また、テスト
count qualified studentsを次のように書き換えます。test "count qualified students" { - let students: Array[Student] = [ + let students: Array[@examine.Student] = [ { id: "0", score: 10.0 }, { id: "1", score: 50.0 }, { id: "2", score: 61.0 }, ] - let criteria1 = fn(student) { is_qualified(student, 10) } - let criteria2 = fn(student) { is_qualified(student, 50) } - assert_eq(count_qualified_students(students, criteria1), 3) - assert_eq(count_qualified_students(students, criteria2), 2) + let criteria1 = fn(student) { @examine.is_qualified(student, 10) } + let criteria2 = fn(student) { @examine.is_qualified(student, 50) } + assert_eq(@examine.count_qualified_students(students, criteria1), 3) + assert_eq(@examine.count_qualified_students(students, criteria2), 2) } - 型と関数へのアクセスに、パッケージ名である
@examineを使用しています。 -
examineは、プロジェクトルートのmoon.mod.jsonで定義されたパッケージ名です。 - 筆者の環境では、この書き換えを行わなくてもテストは通ります。
ライブラリとしてビルドする
- これで、このプロジェクトをMoonBitのモジュールレジストリであるmooncakes.ioに公開できるようになりました。
-
moon loginを実行し、指示に従って既存のGitHubアカウントでアカウントを作成してください。 -
moon.mod.jsonのプロジェクト名を<githubアカウント名>/<プロジェクト名>に変更してください。moon checkを実行して、moon.pkg.jsonに他に変更がないか確認してください。 -
moon publishを実行すれば完了です。このプロジェクトを他のユーザーが利用できるようになります。
チュートリアルは以上です!お疲れ様でした!