moonbit触ってみる
見る
インストール
miseで入れようと思ったが、pluginが無かった
vscodeのMoonBit: Install moonbit toolchainから入れた
.zshrcにexport PATH="$HOME/.moon/bin:$PATH"が追記されていた
shell-completionを入れる
moon shell-completionがある
--helpで詳しい説明が見られる
プロジェクト作成
moon create <project_name>で作れる
ログインしていないとかの警告は一旦無視
プロジェクト名に-は含められないらしい
AGENTS.md最初からあるのモダンですね
ビルド
moon build
デフォルトだとwasm_gcがtarget
_buildに出力された
code: tree
.
├── wasm-gc
│ └── release
│ ├── build
│ │ ├── cmd
│ │ │ └── main
│ │ │ ├── main.core
│ │ │ ├── main.mi
│ │ │ └── main.wasm
│ │ ├── all_pkgs.json
│ │ ├── build.moon_db
│ │ ├── moonbit_todo.core
│ │ └── moonbit_todo.mi
│ └── check
│ ├── cmd
│ │ └── main
│ │ ├── main.blackbox_test.mi
│ │ └── main.mi
│ ├── all_pkgs.json
│ ├── check.moon_db
│ ├── moonbit_todo.blackbox_test.mi
│ └── moonbit_todo.mi
├── .moon-lock
└── packages.json
package.jsonはnpmのそれではない
.miとか.coreってなんだろ
.miがインターフェースの中間表現で、.coreが実装の中間表現なのかな
moonrun _build/wasm-gc/release/build/cmd/main/main.wasmで実行できる
moon build --target js
code: tree
.
├── js
│ └── release
│ └── build
│ ├── cmd
│ │ └── main
│ │ ├── main.core
│ │ ├── main.d.ts
│ │ ├── main.js
│ │ ├── main.mi
│ │ └── moonbit.d.ts
│ ├── all_pkgs.json
│ ├── build.moon_db
│ ├── moonbit_todo.core
│ └── moonbit_todo.mi
main.jsは結構小さそう
builtinも最小限っぽい
cliなのでmain.d.tsはmoonbit.d.tsをimportしているだけで、プリミティブ型のbindingくらいしかない
node _build/js/release/build/cmd/main/main.jsで実行できる
moon build --target native
code: tree
.
├── native
│ └── release
│ └── build
│ ├── cmd
│ │ └── main
│ │ ├── main.c
│ │ ├── main.core
│ │ ├── main.exe
│ │ └── main.mi
│ ├── all_pkgs.json
│ ├── build.moon_db
│ ├── moonbit_todo.core
│ ├── moonbit_todo.mi
│ └── runtime.o
.exeで出力されているが、windows向けの実行ファイルではない
code: zsh
file ./_build/native/release/build/cmd/main/main.exe
./_build/native/release/build/cmd/main/main.exe: Mach-O 64-bit executable arm64
M4 Macで実行している
クロスコンパイルできるのかな?
--target llvmがあるっぽいので、やる方法はありそう
moonbit側の機能としてはまだ無さそうではある
実行
moon run cmd/main
直接実行される
MoonBit Language Tourを読む
Variables
let a: Int = 40で変数宣言
型は省略可能で推論される
デフォルトでイミュータブルなの素晴らしい
ミュータブルはmut let
初期化無しでの宣言はできないぽい
Literals and Types
TypeScriptに慣れていると、整数と浮動小数点が分かれているだけで感動がある
'で囲んだのがChar型、"で囲んだのがString型
CharはUnicodeの1文字なのね
let c = '𩸽'は通るけど、let c2 = '🐈⬛'は通らないみたい
Unit型というのがある
()という一つの値しか持たない
TSのvoid的な
Rust由来らしい
異なる型間の演算はできない?
暗黙的な型変換はない
let a: Int = 42; a.to_float()とかはあるみたい
String And Char
String型はUTF-16
特殊文字は\n, \tとかで書ける
エスケープも\"
テンプレートリテラル的なのは"foo: \{val}"と書ける
ここでは暗黙的にstringに変換されるのか
+でStringの結合もできる
Function
code: mbt
fn add(a: Int, b: Int) -> Int {
return a + b
}
add(2, 3)
パラメータと返り値には明示的な型注釈が必要
code:mbt
fn multiply(x : Int, y : Int) -> Int {
x * y
}
multiply(2, 2)
returnを書かなくても、最後の式が返り値になる
ラベル付きでも書ける
code: mbt
fn print_position(x~ : Int, y~ : Int) -> Unit {
println("(\{x},\{y})")
}
print_position(x=10, y=20)
print_position(10, 20) //はむり
省略可能
code: mbt
fn print_greeting(name? : String = "guest") -> Unit {
println("Hello, " + name + "!")
}
print_greeting()
print_greeting(name="alice")
Block and Statements
ブロックも式である
code:mbt
let result = {
statement
statement2
experession
}
関数同様、最後の式がブロック式の結果として評価される
変数はブロックスコープ
ブロックとは関係無く、変数はshadowingできるみたい
code: mbt
let b = 3.14
let b = 2
println(b) // 2
{
let b = 4
println(b) // 4
}
println(b) // 2
Array
let arr1 : Array[Int] = [1, 2, 3, 4, 5]
ジェネリクスの構文が[]なのかな
配列リテラルの代わりにArray::make(<length>, <val>)でも作れる
長さ
arr.length()
アクセス
arr[1]
負数や長さを超える場合はpanic
スプレッド
let arr3 = [..arr1, 1000, 2000, ..arr2, 3000, 4000]
配列ビュー
元の配列への参照
readonlyでwriteはできない
let view : ArrayView[Int] = arr1[2:4] // [3, 4]
endの方は省略可?で、そのindexの値は含まない
array[start:]
start = endの時はpanicする?
配列の中身に対するwriteは変数自体のイミュータブルとは別